Skip to content

Commit b666125

Browse files
committed
feat: Improve startup times by setting flow.election.max.candidates
1 parent 5cb5bce commit b666125

20 files changed

Lines changed: 35 additions & 64 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ All notable changes to this project will be documented in this file.
1818
- Bump `stackable-operator` to 0.110.1 and `kube` to 3.1.0 ([#921]).
1919
- Internal operator refactoring: introduce dereference() and validate() steps in the reconciler ([#935]).
2020
- Default `nifi.cluster.flow.election.max.wait.time` to NiFi's upstream value (`5 mins`) instead of the operator's previous `1 mins`. The operator no longer sets this property explicitly; the previous shorter value was left over from a TODO marked as "for testing" and may have caused flow election to settle on incomplete vote sets in cold-start scenarios ([#936]).
21+
- In case the user specifies a fixed number of NiFi nodes (i.e. no auto-scaling), set `nifi.cluster.flow.election.max.candidates` to that number.
22+
This results in much faster NiFi startups, as it doesn't need to wait for the 5 minutes of `nifi.cluster.flow.election.max.wait.time` ([#XXX]).
2123
- Set `nifi.content.repository.archive.max.retention.period` to `3 days` (previously empty, which NiFi interprets as `Long.MAX_VALUE` and effectively disables time-based archive purge). Without a time-based ceiling, the content archive can grow to half the content PVC and accumulate millions of files, which makes the synchronous startup directory scan in `FileSystemRepository.initializeRepository` very slow. Users requiring a longer content-replay window can extend via `configOverrides`. The provenance audit trail is independent of this setting and unaffected ([#936]).
2224
- test: Bump vector-aggregator to 0.55.0, replace /graphql call with gRPC call ([#940]).
2325

@@ -34,6 +36,7 @@ All notable changes to this project will be documented in this file.
3436
[#935]: https://github.com/stackabletech/nifi-operator/pull/935
3537
[#936]: https://github.com/stackabletech/nifi-operator/pull/936
3638
[#940]: https://github.com/stackabletech/nifi-operator/pull/940
39+
[#XXX]: https://github.com/stackabletech/nifi-operator/pull/XXX
3740

3841
## [26.3.0] - 2026-03-16
3942

docs/modules/nifi/assets/attachments/entraid-nifi.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,6 @@ spec:
204204
nifi.security.user.oidc.additional.scopes: "profile"
205205
nifi.security.user.oidc.claim.identifying.user: "upn"
206206
nifi.process.group.root.placeholder: "root"
207-
nifi.cluster.flow.election.max.wait.time: "10 secs"
208207
podOverrides:
209208
spec:
210209
initContainers:

docs/modules/nifi/pages/usage_guide/overrides.adoc

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@ For example per role group:
7171
nodes:
7272
roleGroups:
7373
default:
74-
config: {}
7574
replicas: 1
7675
envOverrides:
7776
MY_ENV_VAR: "MY_VALUE"
@@ -86,7 +85,6 @@ nodes:
8685
MY_ENV_VAR: "MY_VALUE"
8786
roleGroups:
8887
default:
89-
config: {}
9088
replicas: 1
9189
----
9290

rust/operator-binary/src/config/mod.rs

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -151,14 +151,15 @@ pub fn build_bootstrap_conf(
151151

152152
/// Create the NiFi nifi.properties
153153
pub fn build_nifi_properties(
154-
spec: &v1alpha1::NifiClusterSpec,
154+
nifi: &v1alpha1::NifiCluster,
155155
resource_config: &Resources<NifiStorageConfig>,
156156
proxy_hosts: &str,
157157
auth_config: &NifiAuthenticationConfig,
158158
overrides: BTreeMap<String, String>,
159159
product_version: &str,
160160
git_sync_resources: &git_sync::v1alpha2::GitSyncResources,
161161
) -> Result<String, Error> {
162+
let cluster_config = &nifi.spec.cluster_config;
162163
// TODO: Remove once we dropped support for all NiFi 1.x versions
163164
let is_nifi_1 = product_version.starts_with("1.");
164165

@@ -278,7 +279,7 @@ pub fn build_nifi_properties(
278279
// The ID of the cluster-wide state provider. This will be ignored if NiFi is not clustered but must be populated if running in a cluster.
279280
properties.insert(
280281
"nifi.state.management.provider.cluster".to_string(),
281-
match spec.cluster_config.clustering_backend {
282+
match cluster_config.clustering_backend {
282283
v1alpha1::NifiClusteringBackend::ZooKeeper { .. } => "zk-provider".to_string(),
283284
v1alpha1::NifiClusteringBackend::Kubernetes { .. } => "kubernetes-provider".to_string(),
284285
},
@@ -528,15 +529,14 @@ pub fn build_nifi_properties(
528529
"".to_string(),
529530
);
530531

531-
let sensitive_properties_algorithm = &spec
532-
.cluster_config
532+
let sensitive_properties_algorithm = cluster_config
533533
.sensitive_properties
534534
.algorithm
535535
.clone()
536536
.unwrap_or_default();
537537

538538
sensitive_properties_algorithm
539-
.check_for_nifi_version(spec.image.product_version())
539+
.check_for_nifi_version(nifi.spec.image.product_version())
540540
.context(ConfigureSensitivePropertiesSnafu)?;
541541

542542
properties.insert(
@@ -609,12 +609,21 @@ pub fn build_nifi_properties(
609609
"nifi.cluster.node.protocol.port".to_string(),
610610
PROTOCOL_PORT.to_string(),
611611
);
612+
613+
// In case the number of NiFi nodes is hard-coded to a fixed (no auto-scaling), we can tell
614+
// this NiFi, so that startup is much quicker.
615+
// Note: In case we don't know the replica count, we set it to "" as that's what we always did
616+
// before.
617+
let max_candidates = nifi
618+
.maybe_fixed_node_count()
619+
.map(|count| count.to_string())
620+
.unwrap_or_default();
612621
properties.insert(
613622
"nifi.cluster.flow.election.max.candidates".to_string(),
614-
"".to_string(),
623+
max_candidates,
615624
);
616625

617-
match spec.cluster_config.clustering_backend {
626+
match cluster_config.clustering_backend {
618627
v1alpha1::NifiClusteringBackend::ZooKeeper { .. } => {
619628
properties.insert(
620629
"nifi.cluster.leader.election.implementation".to_string(),

rust/operator-binary/src/controller.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -756,7 +756,7 @@ async fn build_node_rolegroup_config_map(
756756
.add_data(
757757
NIFI_PROPERTIES,
758758
build_nifi_properties(
759-
&nifi.spec,
759+
nifi,
760760
&merged_config.resources,
761761
proxy_hosts,
762762
authentication_config,

rust/operator-binary/src/crd/mod.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,21 @@ impl v1alpha1::NifiCluster {
289289
tracing::debug!("Merged config: {:?}", conf_rolegroup);
290290
fragment::validate(conf_rolegroup).context(FragmentValidationFailureSnafu)
291291
}
292+
293+
/// Returns [`Some<u32>`] in case the number of nodes is hard-coded to a certain value.
294+
///
295+
/// This is the case when all `replicas` are set to [`Some<u16>`], in which case they are simply
296+
/// summed.
297+
pub fn maybe_fixed_node_count(&self) -> Option<u32> {
298+
self.spec
299+
.nodes
300+
.as_ref()?
301+
.role_groups
302+
.values()
303+
.map(|rg| rg.replicas.map(u32::from))
304+
// As the individual replicas are [`u16`]s, this has plenty space
305+
.sum()
306+
}
292307
}
293308

294309
#[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Serialize)]

tests/templates/kuttl/cluster-sync-cs-bug/20-install-nifi.yaml.j2

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,8 +186,6 @@ spec:
186186
nifi.properties:
187187
nifi.web.https.sni.required: "false"
188188
nifi.web.https.sni.host.check: "false"
189-
# Quicker startup, and we only have a single node
190-
nifi.cluster.flow.election.max.wait.time: "10 secs"
191189
podOverrides:
192190
spec:
193191
initContainers:

tests/templates/kuttl/cluster_operation/20-install-nifi.yaml.j2

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,6 @@ spec:
5050
gracefulShutdownTimeout: 1m
5151
logging:
5252
enableVectorAgent: {{ lookup('env', 'VECTOR_AGGREGATOR') | length > 0 }}
53-
configOverrides:
54-
"nifi.properties":
55-
# Quicker startup, and we only have a single node
56-
"nifi.cluster.flow.election.max.wait.time": "10 secs"
5753
roleGroups:
5854
default:
5955
replicas: 2

tests/templates/kuttl/custom-components-git-sync/30_install-nifi.yaml.j2

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,6 @@ spec:
6767
config:
6868
logging:
6969
enableVectorAgent: {{ lookup('env', 'VECTOR_AGGREGATOR') | length > 0 }}
70-
configOverrides:
71-
"nifi.properties":
72-
# Quicker startup, and we only have a single node
73-
"nifi.cluster.flow.election.max.wait.time": "10 secs"
7470
roleConfig:
7571
listenerClass: external-unstable
7672
podOverrides:

tests/templates/kuttl/external-access/30_nifi.yaml.j2

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,6 @@ spec:
5353
config:
5454
logging:
5555
enableVectorAgent: {{ lookup('env', 'VECTOR_AGGREGATOR') | length > 0 }}
56-
configOverrides:
57-
"nifi.properties":
58-
# Quicker startup, and we only have a single node
59-
"nifi.cluster.flow.election.max.wait.time": "10 secs"
6056
roleConfig:
6157
listenerClass: test-external-unstable-$NAMESPACE
6258
roleGroups:

0 commit comments

Comments
 (0)