Skip to content

Feat(Workflows): Auto-inject inclusive gateways for batch routing#26918

Open
yan-3005 wants to merge 3 commits intoram/workflow-improvementsfrom
ram/inclusive-gateway
Open

Feat(Workflows): Auto-inject inclusive gateways for batch routing#26918
yan-3005 wants to merge 3 commits intoram/workflow-improvementsfrom
ram/inclusive-gateway

Conversation

@yan-3005
Copy link
Copy Markdown
Contributor

@yan-3005 yan-3005 commented Apr 1, 2026

Describe your changes:

Phase 2 of the batch workflow improvements. Builds on Phase 1 (PR #26715) which made all task nodes batch-aware with entity lists.

Problem: Check nodes previously emitted a single RESULT_VARIABLE boolean, which drove exclusive gateway routing — only one branch (true OR false) could fire. In batch mode, a single check node can produce both passing and failing entities simultaneously, so both branches need to fire.

Solution: Auto-inject Flowable inclusive gateways at BPMN build time based on graph structure — no changes needed to workflow JSON definitions.

Changes:

  • InclusiveGatewayBuilder (new) — mirrors ExclusiveGatewayBuilder for InclusiveGateway elements
  • NodeInterface.getOutputPorts() (new default method) — nodes declare which output ports they produce. Only nodes overriding this with ≥2 ports get inclusive gateways injected. UserApprovalTask and other single-result nodes return the default empty set and are unaffected.
  • CheckEntityAttributesTask, CheckChangeDescriptionTask — override getOutputPorts() returning {"true", "false"}
  • DataCompletenessTask — overrides getOutputPorts() returning the configured quality band names (e.g. {"gold", "silver"})
  • Check node impls — removed RESULT_VARIABLE; now emit hasTrueEntities + hasFalseEntities boolean flags (check nodes), or has_<band>_entities per band (DataCompleteness)
  • MainWorkflow — detects split/join points at build time and injects inclusive gateways automatically:
    • Split gateway after any node with getOutputPorts().size() ≥ 2 and ≥2 conditional outgoing edges; conditions map to ${nodeName_hasTrueEntities}, ${nodeName_hasFalseEntities}, ${nodeName_has_<band>_entities}
    • Join gateway before any node with ≥2 incoming edges tracing back to a common split ancestor (BFS upward)

Before (exclusive — only one branch fires):

CheckNode → [${result=='true'}] → PassBranch
          → [${result=='false'}] → FailBranch

After (inclusive — both branches fire when batch has mixed results):

CheckNode → InclusiveGateway(split) → [${check_hasTrueEntities}] → PassBranch
                                    → [${check_hasFalseEntities}] → FailBranch

Type of change:

  • New feature

Checklist:

  • I have read the CONTRIBUTING document.
  • I have added tests around the new logic.

Check nodes (CheckEntityAttributes, CheckChangeDescription, DataCompleteness)
now emit boolean flag variables (hasTrueEntities, hasFalseEntities,
has_<band>_entities) instead of a single RESULT_VARIABLE. MainWorkflow
auto-detects split/join points at BPMN build time via NodeInterface.getOutputPorts()
and injects InclusiveGateways so both true and false branches fire simultaneously
when a batch has mixed pass/fail entities.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@yan-3005 yan-3005 self-assigned this Apr 1, 2026
@yan-3005 yan-3005 requested a review from a team as a code owner April 1, 2026 08:06
@yan-3005 yan-3005 added safe to test Add this label to run secure Github workflows on PRs backend labels Apr 1, 2026
Copilot AI review requested due to automatic review settings April 1, 2026 08:06
@yan-3005 yan-3005 changed the base branch from main to ram/workflow-improvements April 1, 2026 08:08
@yan-3005 yan-3005 changed the title Ram/inclusive gateway Feat(Workflows): Auto-inject inclusive gateways for batch routing Apr 1, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates OpenMetadata governance workflows to support batch entity processing via a new entityList variable, adds inclusive gateway injection for batch “check” nodes (true/false and quality-band branching), and introduces a v1140 migration to update persisted workflow JSON accordingly.

Changes:

  • Replace/augment legacy relatedEntity usage with entityList across workflow triggers, node schemas, and runtime variable handling.
  • Inject inclusive split/join gateways in Flowable BPMN generation for nodes that produce multiple output ports (e.g., check tasks, data completeness bands).
  • Add v1140 migration + extensive unit/integration test updates for new variable semantics and batch entity fetching.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
openmetadata-ui/src/main/resources/ui/src/generated/governance/workflows/elements/nodes/automatedTask/sinkTask.ts Generated UI type updates: InputNamespaceMap now uses entityList and allows additional properties.
openmetadata-ui/src/main/resources/ui/src/generated/governance/workflows/elements/nodes/automatedTask/setEntityAttributeTask.ts Generated UI type updates to entityList-based input namespace map.
openmetadata-ui/src/main/resources/ui/src/generated/governance/workflows/elements/nodes/automatedTask/rollbackEntityTask.ts Generated UI type updates + updated rollback description.
openmetadata-ui/src/main/resources/ui/src/generated/governance/workflows/elements/nodes/automatedTask/dataCompletenessTask.ts Generated UI type updates to entityList-based input namespace map.
openmetadata-ui/src/main/resources/ui/src/generated/governance/workflows/elements/nodes/automatedTask/checkEntityAttributesTask.ts Generated UI type updates + adds output?: string[] on task interface and entityList in namespace map.
openmetadata-ui/src/main/resources/ui/src/generated/governance/workflows/elements/nodes/automatedTask/checkChangeDescriptionTask.ts Generated UI type updates + adds output?: string[] on task interface and entityList in namespace map.
openmetadata-ui/src/main/resources/ui/src/generated/api/governance/createWorkflowDefinition.ts API types updated to include output?: string[] and allow entityList in trigger namespace mapping.
openmetadata-spec/src/main/resources/json/schema/governance/workflows/elements/triggers/periodicBatchEntityTrigger.json Trigger schema output default now includes entityList; relaxes single-item constraint.
openmetadata-spec/src/main/resources/json/schema/governance/workflows/elements/triggers/eventBasedEntityTrigger.json Trigger schema output default now includes entityList; relaxes single-item constraint.
openmetadata-spec/src/main/resources/json/schema/governance/workflows/elements/nodes/automatedTask/sinkTask.json Node schema migrated to require entityList and allow additional properties for conditional keys.
openmetadata-spec/src/main/resources/json/schema/governance/workflows/elements/nodes/automatedTask/setEntityAttributeTask.json Node schema migrated to require entityList and allow additional properties; input defaults/minItems adjusted.
openmetadata-spec/src/main/resources/json/schema/governance/workflows/elements/nodes/automatedTask/rollbackEntityTask.json Node schema migrated to require entityList; description updated to fallback chain.
openmetadata-spec/src/main/resources/json/schema/governance/workflows/elements/nodes/automatedTask/dataCompletenessTask.json Node schema migrated to require entityList; loosens input constraints.
openmetadata-spec/src/main/resources/json/schema/governance/workflows/elements/nodes/automatedTask/checkEntityAttributesTask.json Node schema switches to entityList + adds explicit output defaults for derived entity lists.
openmetadata-spec/src/main/resources/json/schema/governance/workflows/elements/nodes/automatedTask/checkChangeDescriptionTask.json Node schema switches to entityList + adds explicit output defaults for derived entity lists.
openmetadata-service/src/test/java/org/openmetadata/service/migration/utils/v1140/MigrationUtilTest.java New unit tests for v1140 workflow JSON migration behavior.
openmetadata-service/src/test/java/org/openmetadata/service/migration/utils/v1105/MigrationUtilTest.java Updates test fixtures to entityList in workflow JSON.
openmetadata-service/src/test/java/org/openmetadata/service/governance/workflows/flowable/MainWorkflowInclusiveGatewayTest.java New tests verifying inclusive split/join gateway injection logic.
openmetadata-service/src/test/java/org/openmetadata/service/governance/workflows/flowable/builders/InclusiveGatewayBuilderTest.java New unit tests for InclusiveGatewayBuilder.
openmetadata-service/src/test/java/org/openmetadata/service/governance/workflows/elements/nodes/automatedTask/sink/SinkTaskTest.java Updates sink workflow JSON fixtures to entityList.
openmetadata-service/src/test/java/org/openmetadata/service/governance/workflows/elements/nodes/automatedTask/sink/SinkTaskDelegateTest.java Updates delegate tests to batch entity fetching and entityList semantics.
openmetadata-service/src/test/java/org/openmetadata/service/governance/workflows/elements/nodes/automatedTask/SetEntityAttributeTaskTest.java New unit tests for BPMN construction of SetEntityAttribute task with entityList.
openmetadata-service/src/test/java/org/openmetadata/service/governance/workflows/elements/nodes/automatedTask/RollbackEntityTaskTest.java New unit tests for BPMN construction of RollbackEntity task with entityList.
openmetadata-service/src/test/java/org/openmetadata/service/governance/workflows/elements/nodes/automatedTask/impl/SetEntityAttributeImplTest.java New unit tests for batch SetEntityAttributeImpl execution.
openmetadata-service/src/test/java/org/openmetadata/service/governance/workflows/elements/nodes/automatedTask/impl/CheckEntityAttributesImplTest.java New unit tests for batch CheckEntityAttributesImpl execution and flags.
openmetadata-service/src/test/java/org/openmetadata/service/governance/workflows/elements/nodes/automatedTask/impl/CheckChangeDescriptionTaskImplTest.java New unit tests for batch CheckChangeDescriptionTaskImpl execution and flags.
openmetadata-service/src/test/java/org/openmetadata/service/governance/workflows/elements/nodes/automatedTask/DataCompletenessTaskTest.java New unit tests for BPMN construction of DataCompleteness task with entityList.
openmetadata-service/src/test/java/org/openmetadata/service/governance/workflows/elements/nodes/automatedTask/CheckEntityAttributesTaskTest.java New unit tests for BPMN construction of CheckEntityAttributes task with entityList.
openmetadata-service/src/test/java/org/openmetadata/service/governance/workflows/elements/nodes/automatedTask/CheckChangeDescriptionTaskTest.java New unit tests for BPMN construction of CheckChangeDescription task with entityList.
openmetadata-service/src/main/resources/json/data/governance/workflows/GlossaryApprovalWorkflow.json Updates default workflow to emit/use entityList and conditional *_entityList wiring.
openmetadata-service/src/main/java/org/openmetadata/service/migration/utils/v1140/MigrationUtil.java New v1140 migration utility to rewrite stored workflow JSON to entityList + conditional wiring.
openmetadata-service/src/main/java/org/openmetadata/service/migration/utils/v1105/MigrationUtil.java Adds migration logic to rewrite glossary status node namespace map to entityList.
openmetadata-service/src/main/java/org/openmetadata/service/migration/postgres/v1140/Migration.java New Postgres migration entrypoint invoking v1140 workflow migration.
openmetadata-service/src/main/java/org/openmetadata/service/migration/mysql/v1140/Migration.java New MySQL migration entrypoint invoking v1140 workflow migration.
openmetadata-service/src/main/java/org/openmetadata/service/governance/workflows/WorkflowVariableHandler.java Adds getEntityList() helper resolving entity lists from namespace maps (plain and conditional).
openmetadata-service/src/main/java/org/openmetadata/service/governance/workflows/WorkflowEventConsumer.java Ensures event-based trigger variables include both relatedEntity and entityList.
openmetadata-service/src/main/java/org/openmetadata/service/governance/workflows/Workflow.java Adds shared workflow constants for true/false lists and retry configuration.
openmetadata-service/src/main/java/org/openmetadata/service/governance/workflows/flowable/MainWorkflow.java Injects inclusive split/join gateways based on node output ports + conditional edges.
openmetadata-service/src/main/java/org/openmetadata/service/governance/workflows/flowable/builders/InclusiveGatewayBuilder.java New builder for Flowable InclusiveGateway.
openmetadata-service/src/main/java/org/openmetadata/service/governance/workflows/elements/triggers/PeriodicBatchEntityTrigger.java Adjusts periodic trigger call-activity wiring to pass entityList for both single and parallel modes.
openmetadata-service/src/main/java/org/openmetadata/service/governance/workflows/elements/triggers/impl/FilterEntityImpl.java Sets global entityList for event-based flows after filtering.
openmetadata-service/src/main/java/org/openmetadata/service/governance/workflows/elements/triggers/impl/FetchEntitiesImpl.java Sets entityList, numberOfEntities, and entityToListMap for periodic triggers.
openmetadata-service/src/main/java/org/openmetadata/service/governance/workflows/elements/triggers/EventBasedEntityTrigger.java Always passes entityList into the main workflow; avoids duplicating trigger outputs.
openmetadata-service/src/main/java/org/openmetadata/service/governance/workflows/elements/TriggerFactory.java Refines batch-mode detection documentation and logic for trigger execution mode.
openmetadata-service/src/main/java/org/openmetadata/service/governance/workflows/elements/nodes/automatedTask/SinkTask.java Ensures sink task namespace map handling uses defined map and always includes entityList.
openmetadata-service/src/main/java/org/openmetadata/service/governance/workflows/elements/nodes/automatedTask/sink/SinkTaskDelegate.java Switches sink execution to entityList and introduces batched entity fetch + retries.
openmetadata-service/src/main/java/org/openmetadata/service/governance/workflows/elements/nodes/automatedTask/SetEntityAttributeTask.java Ensures BPMN wiring includes default entityList namespace.
openmetadata-service/src/main/java/org/openmetadata/service/governance/workflows/elements/nodes/automatedTask/RollbackEntityTask.java Ensures BPMN wiring includes default entityList namespace.
openmetadata-service/src/main/java/org/openmetadata/service/governance/workflows/elements/nodes/automatedTask/impl/SetEntityAttributeImpl.java Converts to batch processing over entityList with retry + partial failure recording.
openmetadata-service/src/main/java/org/openmetadata/service/governance/workflows/elements/nodes/automatedTask/impl/RollbackEntityImpl.java Converts to batch rollback over entityList with retry + fallback target version selection.
openmetadata-service/src/main/java/org/openmetadata/service/governance/workflows/elements/nodes/automatedTask/impl/DataCompletenessImpl.java Converts to batch completeness evaluation, per-band entity lists, and gateway-ready flags.
openmetadata-service/src/main/java/org/openmetadata/service/governance/workflows/elements/nodes/automatedTask/impl/CheckEntityAttributesImpl.java Converts to batch rule evaluation producing true/false entity lists and flags.
openmetadata-service/src/main/java/org/openmetadata/service/governance/workflows/elements/nodes/automatedTask/impl/CheckChangeDescriptionTaskImpl.java Converts to batch change-description evaluation producing true/false entity lists and flags.
openmetadata-service/src/main/java/org/openmetadata/service/governance/workflows/elements/nodes/automatedTask/DataCompletenessTask.java Declares output ports (bands) and defaults entityList mapping for gateway injection.
openmetadata-service/src/main/java/org/openmetadata/service/governance/workflows/elements/nodes/automatedTask/CheckEntityAttributesTask.java Declares output ports (true/false) and defaults entityList mapping for gateway injection.
openmetadata-service/src/main/java/org/openmetadata/service/governance/workflows/elements/nodes/automatedTask/CheckChangeDescriptionTask.java Declares output ports (true/false) and defaults entityList mapping for gateway injection.
openmetadata-service/src/main/java/org/openmetadata/service/governance/workflows/elements/NodeInterface.java Adds getOutputPorts() hook used for inclusive gateway detection.
openmetadata-service/src/main/java/org/openmetadata/service/Entity.java Adds getEntitiesByLinks() helper for efficient batch entity fetch by entity link strings.
openmetadata-integration-tests/src/test/java/org/openmetadata/it/tests/WorkflowDefinitionResourceIT.java Updates integration tests to build/validate workflows using entityList and new outputs.

Comment on lines +33 to +47
// Workflow: start → check → cert(true) / notify(false) → independent ends
WorkflowDefinition workflow =
createWorkflow(
"SplitOnlyWorkflow",
List.of(
startEvent("start"),
checkAttributesNode("check"),
endEvent("certEnd"),
endEvent("notifyEnd")),
List.of(
edge("start", "check", null),
edge("check", "cert", "true"),
edge("check", "notify", "false"),
edge("cert", "certEnd", null),
edge("notify", "notifyEnd", null)));
Copy link

Copilot AI Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test workflow defines edges to node ids (e.g. cert, notify) that are not included in the nodes list. That can produce a BPMN model with SequenceFlow targets/sources that don't exist, making the test less representative and potentially hiding issues if workflow validation becomes stricter. Consider adding minimal node definitions for cert/notify (or update edges to point to existing nodes) so the constructed workflow is structurally valid.

Copilot uses AI. Check for mistakes.
…ferences

- Check nodes (CheckEntityAttributes, CheckChangeDescription) now set
  hasFalseEntities=true when entity list is empty, ensuring the split
  inclusive gateway always has at least one active branch and never stalls.
- DataCompletenessImpl activates the lowest-score band flag when no entities
  are assigned to any band (empty input or all entities failed processing).
- MainWorkflowInclusiveGatewayTest: replaced dangling edge targets (cert,
  notify, goldAction etc.) with actual declared end-event nodes so the
  constructed BPMN model is structurally valid.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 1, 2026

Jest test Coverage

UI tests summary

Lines Statements Branches Functions
Coverage: 64%
64.87% (58823/90674) 44.47% (30904/69491) 47.69% (9336/19576)

@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud bot commented Apr 1, 2026

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 1, 2026

🔴 Playwright Results — 7 failure(s), 27 flaky

✅ 3432 passed · ❌ 7 failed · 🟡 27 flaky · ⏭️ 223 skipped

Shard Passed Failed Flaky Skipped
🟡 Shard 1 451 0 4 2
🔴 Shard 2 607 4 7 32
🟡 Shard 3 615 0 5 27
🟡 Shard 4 619 0 5 47
✅ Shard 5 587 0 0 67
🔴 Shard 6 553 3 6 48

Genuine Failures (failed on all attempts)

Features/AdvancedSearch.spec.ts › Verify Rule functionality for field Status with AND operator (shard 2)
�[31mTest timeout of 180000ms exceeded.�[39m
Features/AdvancedSearch.spec.ts › Verify Group functionality for field Status with AND operator (shard 2)
�[31mTest timeout of 180000ms exceeded.�[39m
Features/AdvancedSearch.spec.ts › Verify Rule functionality for field Status with OR operator (shard 2)
�[31mTest timeout of 180000ms exceeded.�[39m
Features/AdvancedSearch.spec.ts › Verify Group functionality for field Status with OR operator (shard 2)
�[31mTest timeout of 180000ms exceeded.�[39m
Pages/Glossary.spec.ts › Glossary & terms creation for reviewer as user (shard 6)
Error: To get the last run execution status as success

�[2mexpect(�[22m�[31mreceived�[39m�[2m).�[22mtoContain�[2m(�[22m�[32mexpected�[39m�[2m) // indexOf�[22m

Expected value: �[32m"PW.31ef0ba2%Falcon8ffc934f"�[39m
Received array: �[31m[]�[39m

Call Log:
- Test timeout of 180000ms exceeded
Pages/Glossary.spec.ts › Glossary & terms creation for reviewer as team (shard 6)
TypeError: Cannot read properties of undefined (reading 'map')
Pages/Glossary.spec.ts › Approve and reject glossary term from Glossary Listing (shard 6)
Error: To get the last run execution status as success

�[2mexpect(�[22m�[31mreceived�[39m�[2m).�[22mtoContain�[2m(�[22m�[32mexpected�[39m�[2m) // indexOf�[22m

Expected value: �[32m"PW.0cc93c23%Panda8895af8e"�[39m
Received array: �[31m[]�[39m

Call Log:
- Test timeout of 180000ms exceeded
🟡 27 flaky test(s) (passed on retry)
  • Features/DataAssetRulesDisabled.spec.ts › Verify the Pipeline entity item action after rules disabled (shard 1, 1 retry)
  • Features/CustomizeDetailPage.spec.ts › Database Schema - customization should work (shard 1, 1 retry)
  • Flow/Tour.spec.ts › Tour should work from URL directly (shard 1, 1 retry)
  • Pages/UserCreationWithPersona.spec.ts › Create user with persona and verify on profile (shard 1, 1 retry)
  • Features/BulkEditEntity.spec.ts › Database Schema (shard 2, 1 retry)
  • Features/BulkEditEntity.spec.ts › Glossary (shard 2, 1 retry)
  • Features/BulkImport.spec.ts › Database Schema (shard 2, 1 retry)
  • Features/BulkImport.spec.ts › Keyboard Delete selection (shard 2, 1 retry)
  • Features/DataProductRenameConsolidation.spec.ts › Multiple rename + update cycles - assets should be preserved (shard 2, 1 retry)
  • Features/DataQuality/BundleSuiteBulkOperations.spec.ts › Bulk selection operations (shard 2, 1 retry)
  • Features/DataQuality/ColumnLevelTests.spec.ts › Column Values Sum To Be Between (shard 2, 1 retry)
  • Features/ImpactAnalysis.spec.ts › verify owner filter for Asset level impact analysis (shard 3, 1 retry)
  • Features/Permissions/GlossaryPermissions.spec.ts › Team-based permissions work correctly (shard 3, 1 retry)
  • Features/Table.spec.ts › Tags term should be consistent for search (shard 3, 1 retry)
  • Flow/CustomizeWidgets.spec.ts › Activity Feed Widget (shard 3, 1 retry)
  • Flow/ExploreDiscovery.spec.ts › Should display deleted assets when showDeleted is checked and deleted is not present in queryFilter (shard 3, 1 retry)
  • Pages/Customproperties-part2.spec.ts › entityReferenceList shows item count, scrollable list, no expand toggle (shard 4, 1 retry)
  • Pages/DataContractsSemanticRules.spec.ts › Validate Description Rule Is_Not_Set (shard 4, 1 retry)
  • Pages/DomainDataProductsRightPanel.spec.ts › Should edit owners for data product from domain context (shard 4, 1 retry)
  • Pages/Domains.spec.ts › Data Product announcement create, edit & delete (shard 4, 1 retry)
  • Pages/Entity.spec.ts › Set & Update table-cp, hyperlink-cp, string, integer, markdown, number, duration, email, enum, sqlQuery, timestamp, entityReference, entityReferenceList, timeInterval, time-cp, date-cp, dateTime-cp Custom Property (shard 4, 1 retry)
  • Pages/Glossary.spec.ts › Add and Remove Assets (shard 6, 1 retry)
  • Pages/Glossary.spec.ts › Column dropdown drag-and-drop functionality for Glossary Terms table (shard 6, 1 retry)
  • Pages/Glossary.spec.ts › Create glossary, change language to Dutch, and delete glossary (shard 6, 1 retry)
  • Pages/InputOutputPorts.spec.ts › Lineage section collapse/expand (shard 6, 1 retry)
  • Pages/UserDetails.spec.ts › Create team with domain and verify visibility of inherited domain in user profile after team removal (shard 6, 1 retry)
  • Pages/Users.spec.ts › Permissions for table details page for Data Consumer (shard 6, 1 retry)

📦 Download artifacts

How to debug locally
# Download playwright-test-results-<shard> artifact and unzip
npx playwright show-trace path/to/trace.zip    # view trace

- DataCompletenessTask: guard against null getQualityBands() with Optional
- DataCompletenessImpl: extract bandFlagVariable() static helper used by
  both the impl and MainWorkflow to avoid naming convention drift
- InclusiveGatewayBuilder: remove misleading exclusive() setter; async job
  exclusivity is hardcoded true (not a routing concern, matches ExclusiveGatewayBuilder)
- MainWorkflow: add @slf4j + warn log when a conditional edge targets a join
  node (condition is intentionally ignored); use DataCompletenessImpl.bandFlagVariable()
- DataCompletenessImplTest: add tests for empty entity list and all-entities-fail
  scenarios, both verifying lowest-band flag is activated as deadlock fallback

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
public DataCompletenessTask(
DataCompletenessTaskDefinition nodeDefinition, WorkflowConfiguration workflowConfig) {
this.outputPorts =
Optional.ofNullable(nodeDefinition.getConfig().getQualityBands()).orElse(List.of()).stream()
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Edge Case: Null guard on getQualityBands() but not on getConfig()

Line 44 wraps getQualityBands() with Optional.ofNullable() to handle a null band list, but getConfig() in the same call chain is not guarded. If getConfig() ever returns null, this will throw an NPE before the Optional even kicks in. While the JSON schema marks config as required (reducing the risk), other task nodes like CheckChangeDescriptionTask defensively null-check getConfig() as well. For consistency and resilience, the entire chain should be guarded.

Suggested fix:

Optional.ofNullable(nodeDefinition.getConfig())
    .map(DataCompletenessTaskDefinition.DataCompletenessTaskConfig::getQualityBands)
    .orElse(List.of()).stream()
    .map(QualityBand::getName)
    .collect(Collectors.toSet());

Was this helpful? React with 👍 / 👎 | Reply gitar fix to apply this suggestion

@gitar-bot
Copy link
Copy Markdown

gitar-bot bot commented Apr 1, 2026

Code Review 👍 Approved with suggestions 2 resolved / 4 findings

Auto-inject inclusive gateways feature now handles empty entity lists without deadlocking and prevents silent failures in RollbackEntityImpl. Consider removing unnecessary retry logic from in-memory computation in DataCompletenessImpl and adding null guard on getConfig() for consistency with getQualityBands().

💡 Performance: Retry wraps pure in-memory computation in DataCompletenessImpl

📄 openmetadata-service/src/main/java/org/openmetadata/service/governance/workflows/elements/nodes/automatedTask/impl/DataCompletenessImpl.java:63 📄 openmetadata-service/src/main/java/org/openmetadata/service/governance/workflows/elements/nodes/automatedTask/impl/DataCompletenessImpl.java:74-80

In DataCompletenessImpl (lines 74-80), calculateCompleteness() is wrapped with Retry.decorateSupplier(). However, calculateCompleteness is a pure in-memory computation over JsonUtils.getMap(entity) — it performs no I/O, no database access, and no network calls. Retrying it will always produce the same result (or the same exception). The retry adds overhead (creating Retry instance, wrapping supplier) with no benefit.

Other task impls (CheckEntityAttributes, SetEntityAttribute) correctly apply retry only around I/O operations like RuleEngine or EntityFieldUtils.

💡 Edge Case: Null guard on getQualityBands() but not on getConfig()

📄 openmetadata-service/src/main/java/org/openmetadata/service/governance/workflows/elements/nodes/automatedTask/DataCompletenessTask.java:44

Line 44 wraps getQualityBands() with Optional.ofNullable() to handle a null band list, but getConfig() in the same call chain is not guarded. If getConfig() ever returns null, this will throw an NPE before the Optional even kicks in. While the JSON schema marks config as required (reducing the risk), other task nodes like CheckChangeDescriptionTask defensively null-check getConfig() as well. For consistency and resilience, the entire chain should be guarded.

Suggested fix
Optional.ofNullable(nodeDefinition.getConfig())
    .map(DataCompletenessTaskDefinition.DataCompletenessTaskConfig::getQualityBands)
    .orElse(List.of()).stream()
    .map(QualityBand::getName)
    .collect(Collectors.toSet());
✅ 2 resolved
Edge Case: Inclusive gateway deadlocks when entity list is empty

📄 openmetadata-service/src/main/java/org/openmetadata/service/governance/workflows/elements/nodes/automatedTask/impl/CheckEntityAttributesImpl.java:73-76 📄 openmetadata-service/src/main/java/org/openmetadata/service/governance/workflows/elements/nodes/automatedTask/impl/CheckChangeDescriptionTaskImpl.java:81-84 📄 openmetadata-service/src/main/java/org/openmetadata/service/governance/workflows/flowable/MainWorkflow.java:74-87 📄 openmetadata-service/src/main/java/org/openmetadata/service/Entity.java:659-662 📄 openmetadata-service/src/main/java/org/openmetadata/service/governance/workflows/elements/nodes/automatedTask/impl/CheckEntityAttributesImpl.java:45-46 📄 openmetadata-service/src/main/java/org/openmetadata/service/governance/workflows/elements/nodes/automatedTask/impl/CheckChangeDescriptionTaskImpl.java:49-50
When a check node (CheckEntityAttributesImpl, CheckChangeDescriptionTaskImpl) receives an empty entity list, both HAS_TRUE_ENTITIES_VARIABLE and HAS_FALSE_ENTITIES_VARIABLE are set to false. The split inclusive gateway then has no condition evaluating to true, so no outgoing branch activates. In Flowable, an inclusive gateway with zero active outgoing flows causes the process token to stall permanently — the workflow instance never completes.

This can happen if: (1) a conditional entity list from an upstream node is empty (all entities went to the other branch), (2) entities were deleted between trigger and task execution, or (3) getEntityList() returns an empty list due to missing variables.

The same issue applies to DataCompletenessImpl where all band flags could be false if all entities fail processing.

Consider adding a default flow to the split inclusive gateway, or guarding against empty entity lists before the gateway is reached (e.g., skip the node entirely if the list is empty).

Edge Case: RollbackEntityImpl silently continues on total failure

📄 openmetadata-service/src/main/java/org/openmetadata/service/governance/workflows/elements/nodes/automatedTask/impl/RollbackEntityImpl.java:91-101
When all entities fail in RollbackEntityImpl, the processingStatus is set to "failure" and the EXCEPTION_VARIABLE is populated, but no BpmnError is thrown. The task completes normally even though every entity failed to rollback. This means the workflow continues to downstream nodes as if rollback succeeded.

By contrast, the outer catch block (line 103-109) does throw BpmnError for unexpected exceptions. Consider throwing BpmnError (or at least setting the failure variable) when failedEntities.size() == entityList.size() to halt the workflow on complete failure.

🤖 Prompt for agents
Code Review: Auto-inject inclusive gateways feature now handles empty entity lists without deadlocking and prevents silent failures in RollbackEntityImpl. Consider removing unnecessary retry logic from in-memory computation in DataCompletenessImpl and adding null guard on getConfig() for consistency with getQualityBands().

1. 💡 Performance: Retry wraps pure in-memory computation in DataCompletenessImpl
   Files: openmetadata-service/src/main/java/org/openmetadata/service/governance/workflows/elements/nodes/automatedTask/impl/DataCompletenessImpl.java:63, openmetadata-service/src/main/java/org/openmetadata/service/governance/workflows/elements/nodes/automatedTask/impl/DataCompletenessImpl.java:74-80

   In DataCompletenessImpl (lines 74-80), `calculateCompleteness()` is wrapped with `Retry.decorateSupplier()`. However, `calculateCompleteness` is a pure in-memory computation over `JsonUtils.getMap(entity)` — it performs no I/O, no database access, and no network calls. Retrying it will always produce the same result (or the same exception). The retry adds overhead (creating Retry instance, wrapping supplier) with no benefit.
   
   Other task impls (CheckEntityAttributes, SetEntityAttribute) correctly apply retry only around I/O operations like RuleEngine or EntityFieldUtils.

2. 💡 Edge Case: Null guard on getQualityBands() but not on getConfig()
   Files: openmetadata-service/src/main/java/org/openmetadata/service/governance/workflows/elements/nodes/automatedTask/DataCompletenessTask.java:44

   Line 44 wraps `getQualityBands()` with `Optional.ofNullable()` to handle a null band list, but `getConfig()` in the same call chain is not guarded. If `getConfig()` ever returns null, this will throw an NPE before the Optional even kicks in. While the JSON schema marks `config` as required (reducing the risk), other task nodes like `CheckChangeDescriptionTask` defensively null-check `getConfig()` as well. For consistency and resilience, the entire chain should be guarded.

   Suggested fix:
   Optional.ofNullable(nodeDefinition.getConfig())
       .map(DataCompletenessTaskDefinition.DataCompletenessTaskConfig::getQualityBands)
       .orElse(List.of()).stream()
       .map(QualityBand::getName)
       .collect(Collectors.toSet());

Options

Display: compact → Showing less information.

Comment with these commands to change:

Compact
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud bot commented Apr 1, 2026

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend safe to test Add this label to run secure Github workflows on PRs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants