Xinyu Wang created NIFI-16440:
---------------------------------
Summary: Provided Parameters stay empty after restart once a
failed Parameter Provider fetch has dropped their value from flow.json
Key: NIFI-16440
URL: https://issues.apache.org/jira/browse/NIFI-16440
Project: Apache NiFi
Issue Type: Bug
Components: Core Framework
Affects Versions: 2.12.0, 2.0.0
Reporter: Xinyu Wang
h3. Problem
NIFI-13560 (first released in 2.0.0) stopped persisting values fetched from a
Parameter Provider. The flow configuration only keeps a reference
({{provided:parameter}}) and NiFi fetches the values again when it starts. If
the Parameter Provider cannot be reached during that startup fetch, the
reference is lost and the Parameters cannot recover on later restarts, even
after the provider is healthy again.
h3. Steps to reproduce
# Configure a Parameter Provider and apply its Parameter Group so that a
Parameter Context is bound to it. All Parameters have values.
# Make the provider unreachable and restart NiFi. The startup fetch fails,
{{Fetched Parameters [0]}} is logged, and every provided Parameter is empty.
This part is expected.
# Make the provider reachable again.
# Restart NiFi, as many times as you like.
h3. Actual behavior
On every restart in step 4 the provider returns all Parameters ({{Fetched
Parameters [4]}}), but every Parameter stays empty. The only way back is *Fetch
Parameters* followed by *Apply Changes*.
In flow.json the provided Parameters were serialized as
{code}{"name":"key1","sensitive":false,"provided":true,"value":"provided:parameter"}{code}
before step 2, and after step 2 they have *no {{value}} field at all*:
{code}{"name":"key1","sensitive":false,"provided":true}{code}
h3. Expected behavior
Once the provider is reachable again, the next restart fetches the values and
the Parameters are populated. A failed fetch should not remove the reference to
the provider from the flow configuration.
h3. Root cause
Two null checks run before the provided check:
# {{StandardParameterValueMapper.getMapped}} evaluates {{value == null}} before
{{parameter.isProvided()}} (added in NIFI-13577 to avoid an NPE in the
sensitive value encryptor). After a failed fetch the Parameter value is null,
so the mapper returns null and the {{value}} field is omitted when flow.json is
written.
# {{VersionedFlowSynchronizer}} (the method that builds the Parameter map from
the serialized Parameter Context) evaluates {{rawValue == null}} before the
provided check. A provided Parameter without a stored value is set to null
without looking at the values fetched from the provider.
The failed fetch itself is only logged ({{Fetching Parameters for Group [...]
from Provider [...] failed}}), then each provided Parameter logs {{Provided
Parameter [x] not found}} and gets a null value. This happens for any provider
whose {{fetchParameters}} throws, for example when the external service is
unavailable during startup.
h3. Proposed fix
Evaluate {{isProvided()}} first in both places:
* {{StandardParameterValueMapper.getMapped}}: return {{provided:parameter}} for
provided Parameters even when the value is null.
* {{VersionedFlowSynchronizer}}: for provided Parameters always use the value
from the provider, regardless of the stored value.
With this change the flow configuration keeps {{provided:parameter}} through a
failed fetch, and the Parameters recover on the next restart after the provider
is back (verified on 2.12.0, see below). Non-provided Parameters are not
affected.
h3. Verification
Tested on stock {{apache/nifi}} images, standalone, with a Parameter Provider
that throws {{IOException}} when its backend is down. The "without fix" column
was reproduced on both 2.0.0 and 2.12.0 with identical results; the "with fix"
column was tested on 2.12.0:
|| Scenario || Without fix || With fix ||
| provider down, restart | Parameters empty, {{value}} dropped from flow.json |
Parameters empty, {{provided:parameter}} kept in flow.json |
| provider up again, restart (repeat 3 times) | Parameters stay empty every
time | Parameters populated after one restart |
| flow.json already missing {{value}} | stays empty | populated after one
restart |
h3. Notes
* Existing unit test {{TestStandardParameterValueMapper}} covers a null value
for a non-provided Parameter only; a provided Parameter with a null value is
not covered.
* Related: NIFI-13560 (design), NIFI-13577 (null handling in the mapper),
NIFI-13688 (startup ordering of provider validation).
--
This message was sent by Atlassian Jira
(v8.20.10#820010)