-
Notifications
You must be signed in to change notification settings - Fork 2k
[WIP] feat(workflows): batch entity processing — entityList-only for automated task nodes #26715
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
0ec257c
e635e2f
fb2e2b4
90b6325
5cc175a
ea9a384
39880fe
676740c
0280942
3b191e8
88c5f0e
883ebd8
fb283ec
685bdb4
96bc193
996928a
7a75510
7e2af14
5c2479c
6394c3f
1f96932
93133fc
5bdc592
12441aa
4930d3c
7ced433
889ca1a
0820069
a0d4457
b92bb1c
024d8ba
abf6442
03a321a
de4ae6c
26cb774
7fadb00
2077ecd
a631c29
63f3940
c1fa551
8eede11
1497060
216b6a0
c8ab3ae
793dcd2
41f728d
339d32f
0f9cfcf
ccbd1df
06b2be6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -33,6 +33,7 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.util.EnumMap; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.util.HashMap; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.util.HashSet; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.util.LinkedHashMap; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.util.List; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.util.Locale; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.util.Map; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -652,6 +653,37 @@ public static <T> T getEntity(EntityLink link, String fields, Include include) { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return getEntityByName(link.getEntityType(), link.getEntityFQN(), fields, include); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public static Map<String, EntityInterface> getEntitiesByLinks( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| List<String> entityLinkStrs, String fields, Include include) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (entityLinkStrs == null || entityLinkStrs.isEmpty()) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return Map.of(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // All entity links in a workflow's entityList are always the same entity type — | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // event-based triggers fire for a single entity, and periodic batch triggers are configured | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // with one entity type. The type is taken from the first link. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Map<String, String> linkToFqn = new LinkedHashMap<>(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| String entityType = null; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (String linkStr : entityLinkStrs) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| EntityLink link = EntityLink.parse(linkStr); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (entityType == null) entityType = link.getEntityType(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| linkToFqn.put(linkStr, link.getEntityFQN()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| List<EntityInterface> entities = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| getEntityByNames(entityType, new ArrayList<>(linkToFqn.values()), fields, include); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Map<String, EntityInterface> fqnToEntity = new HashMap<>(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (EntityInterface entity : entities) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fqnToEntity.put(entity.getFullyQualifiedName(), entity); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Map<String, EntityInterface> result = new LinkedHashMap<>(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (Map.Entry<String, String> entry : linkToFqn.entrySet()) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| EntityInterface entity = fqnToEntity.get(entry.getValue()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (entity != null) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| result.put(entry.getKey(), entity); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+661
to
+681
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // All entity links in a workflow's entityList are always the same entity type — | |
| // event-based triggers fire for a single entity, and periodic batch triggers are configured | |
| // with one entity type. The type is taken from the first link. | |
| Map<String, String> linkToFqn = new LinkedHashMap<>(); | |
| String entityType = null; | |
| for (String linkStr : entityLinkStrs) { | |
| EntityLink link = EntityLink.parse(linkStr); | |
| if (entityType == null) entityType = link.getEntityType(); | |
| linkToFqn.put(linkStr, link.getEntityFQN()); | |
| } | |
| List<EntityInterface> entities = | |
| getEntityByNames(entityType, new ArrayList<>(linkToFqn.values()), fields, include); | |
| Map<String, EntityInterface> fqnToEntity = new HashMap<>(); | |
| for (EntityInterface entity : entities) { | |
| fqnToEntity.put(entity.getFullyQualifiedName(), entity); | |
| } | |
| Map<String, EntityInterface> result = new LinkedHashMap<>(); | |
| for (Map.Entry<String, String> entry : linkToFqn.entrySet()) { | |
| EntityInterface entity = fqnToEntity.get(entry.getValue()); | |
| if (entity != null) { | |
| result.put(entry.getKey(), entity); | |
| // Parse all links defensively and allow mixed entity types. A single malformed | |
| // link should not abort processing of the whole list. | |
| Map<String, EntityLink> linkStrToLink = new LinkedHashMap<>(); | |
| for (String linkStr : entityLinkStrs) { | |
| if (linkStr == null) { | |
| LOG.warn("Skipping null entity link string"); | |
| continue; | |
| } | |
| try { | |
| EntityLink link = EntityLink.parse(linkStr); | |
| linkStrToLink.put(linkStr, link); | |
| } catch (IllegalArgumentException | BadRequestException ex) { | |
| LOG.warn("Skipping invalid entity link '{}': {}", linkStr, ex.getMessage()); | |
| } | |
| } | |
| if (linkStrToLink.isEmpty()) { | |
| return Map.of(); | |
| } | |
| // Group FQNs by entity type so we can fetch them in batches per type. | |
| Map<String, List<String>> entityTypeToFqns = new LinkedHashMap<>(); | |
| for (EntityLink link : linkStrToLink.values()) { | |
| entityTypeToFqns | |
| .computeIfAbsent(link.getEntityType(), k -> new ArrayList<>()) | |
| .add(link.getEntityFQN()); | |
| } | |
| Map<String, EntityInterface> fqnToEntity = new HashMap<>(); | |
| for (Map.Entry<String, List<String>> entry : entityTypeToFqns.entrySet()) { | |
| String entityType = entry.getKey(); | |
| List<String> fqns = entry.getValue(); | |
| if (fqns.isEmpty()) { | |
| continue; | |
| } | |
| List<EntityInterface> entitiesForType = | |
| getEntityByNames(entityType, fqns, fields, include); | |
| for (EntityInterface entity : entitiesForType) { | |
| if (entity != null && entity.getFullyQualifiedName() != null) { | |
| fqnToEntity.put(entity.getFullyQualifiedName(), entity); | |
| } | |
| } | |
| } | |
| Map<String, EntityInterface> result = new LinkedHashMap<>(); | |
| for (Map.Entry<String, EntityLink> entry : linkStrToLink.entrySet()) { | |
| String linkStr = entry.getKey(); | |
| EntityLink link = entry.getValue(); | |
| EntityInterface entity = fqnToEntity.get(link.getEntityFQN()); | |
| if (entity != null) { | |
| result.put(linkStr, entity); |
Copilot
AI
Mar 31, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getEntitiesByLinks (1) assumes all entity links share the same entity type (uses the first link’s type for the entire fetch), and (2) will throw if any link string is malformed (EntityLink.parse). In batch workflows, a single bad link can cause the whole node execution to fail instead of being isolated to that entity. Consider validating that all links are the same type (or grouping by type), and handling parse failures per-link (skip/collect errors) so callers can continue processing remaining entities.
| Map<String, String> linkToFqn = new LinkedHashMap<>(); | |
| String entityType = null; | |
| for (String linkStr : entityLinkStrs) { | |
| EntityLink link = EntityLink.parse(linkStr); | |
| if (entityType == null) entityType = link.getEntityType(); | |
| linkToFqn.put(linkStr, link.getEntityFQN()); | |
| } | |
| List<EntityInterface> entities = | |
| getEntityByNames(entityType, new ArrayList<>(linkToFqn.values()), fields, include); | |
| Map<String, EntityInterface> fqnToEntity = new HashMap<>(); | |
| for (EntityInterface entity : entities) { | |
| fqnToEntity.put(entity.getFullyQualifiedName(), entity); | |
| } | |
| Map<String, EntityInterface> result = new LinkedHashMap<>(); | |
| for (Map.Entry<String, String> entry : linkToFqn.entrySet()) { | |
| EntityInterface entity = fqnToEntity.get(entry.getValue()); | |
| if (entity != null) { | |
| result.put(entry.getKey(), entity); | |
| } | |
| } | |
| // Group links by entity type and handle parse failures per-link. | |
| Map<String, Map<String, String>> typeToLinkToFqn = new LinkedHashMap<>(); | |
| for (String linkStr : entityLinkStrs) { | |
| if (linkStr == null) { | |
| continue; | |
| } | |
| try { | |
| EntityLink link = EntityLink.parse(linkStr); | |
| String entityType = link.getEntityType(); | |
| String entityFqn = link.getEntityFQN(); | |
| typeToLinkToFqn | |
| .computeIfAbsent(entityType, k -> new LinkedHashMap<>()) | |
| .put(linkStr, entityFqn); | |
| } catch (RuntimeException e) { | |
| // Skip malformed links but continue processing other links. | |
| log.warn("Failed to parse entity link '{}'", linkStr, e); | |
| } | |
| } | |
| if (typeToLinkToFqn.isEmpty()) { | |
| // No valid links parsed. | |
| return Map.of(); | |
| } | |
| Map<String, EntityInterface> fqnToEntity = new HashMap<>(); | |
| for (Map.Entry<String, Map<String, String>> entry : typeToLinkToFqn.entrySet()) { | |
| String entityType = entry.getKey(); | |
| Map<String, String> linkToFqn = entry.getValue(); | |
| if (linkToFqn.isEmpty()) { | |
| continue; | |
| } | |
| List<EntityInterface> entities = | |
| getEntityByNames(entityType, new ArrayList<>(linkToFqn.values()), fields, include); | |
| for (EntityInterface entity : entities) { | |
| if (entity != null && entity.getFullyQualifiedName() != null) { | |
| fqnToEntity.put(entity.getFullyQualifiedName(), entity); | |
| } | |
| } | |
| } | |
| Map<String, EntityInterface> result = new LinkedHashMap<>(); | |
| for (Map.Entry<String, Map<String, String>> typeEntry : typeToLinkToFqn.entrySet()) { | |
| Map<String, String> linkToFqn = typeEntry.getValue(); | |
| for (Map.Entry<String, String> linkEntry : linkToFqn.entrySet()) { | |
| EntityInterface entity = fqnToEntity.get(linkEntry.getValue()); | |
| if (entity != null) { | |
| result.put(linkEntry.getKey(), entity); | |
| } | |
| } | |
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| /* | ||
| * Copyright 2021 Collate | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
|
|
||
| package org.openmetadata.service.config; | ||
|
|
||
| import com.fasterxml.jackson.annotation.JsonProperty; | ||
| import java.util.Collections; | ||
| import java.util.Map; | ||
| import org.openmetadata.service.config.web.HeaderFactory; | ||
|
|
||
| public class CrossOriginEmbedderPolicyHeaderFactory extends HeaderFactory { | ||
| public static final String CROSS_ORIGIN_EMBEDDER_POLICY_HEADER = "Cross-Origin-Embedder-Policy"; | ||
|
|
||
| @JsonProperty("option") | ||
| private String option; | ||
|
|
||
| public CrossOriginEmbedderPolicyHeaderFactory() {} | ||
|
|
||
| public String getOption() { | ||
| return this.option; | ||
| } | ||
|
|
||
| public void setOption(String option) { | ||
| this.option = option; | ||
| } | ||
|
|
||
| @Override | ||
| protected Map<String, String> buildHeaders() { | ||
| return Collections.singletonMap(CROSS_ORIGIN_EMBEDDER_POLICY_HEADER, this.option); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| /* | ||
| * Copyright 2021 Collate | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
|
|
||
| package org.openmetadata.service.config; | ||
|
|
||
| import com.fasterxml.jackson.annotation.JsonProperty; | ||
| import java.util.Collections; | ||
| import java.util.Map; | ||
| import org.openmetadata.service.config.web.HeaderFactory; | ||
|
|
||
| public class CrossOriginOpenerPolicyHeaderFactory extends HeaderFactory { | ||
| public static final String CROSS_ORIGIN_OPENER_POLICY_HEADER = "Cross-Origin-Opener-Policy"; | ||
|
|
||
| @JsonProperty("option") | ||
| private String option; | ||
|
|
||
| public CrossOriginOpenerPolicyHeaderFactory() {} | ||
|
|
||
| public String getOption() { | ||
| return this.option; | ||
| } | ||
|
|
||
| public void setOption(String option) { | ||
| this.option = option; | ||
| } | ||
|
|
||
| @Override | ||
| protected Map<String, String> buildHeaders() { | ||
| return Collections.singletonMap(CROSS_ORIGIN_OPENER_POLICY_HEADER, this.option); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| /* | ||
| * Copyright 2021 Collate | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
|
|
||
| package org.openmetadata.service.config; | ||
|
|
||
| import com.fasterxml.jackson.annotation.JsonProperty; | ||
| import java.util.Collections; | ||
| import java.util.Map; | ||
| import org.openmetadata.service.config.web.HeaderFactory; | ||
|
|
||
| public class CrossOriginResourcePolicyHeaderFactory extends HeaderFactory { | ||
| public static final String CROSS_ORIGIN_RESOURCE_POLICY_HEADER = "Cross-Origin-Resource-Policy"; | ||
|
|
||
| @JsonProperty("option") | ||
| private String option; | ||
|
|
||
| public CrossOriginResourcePolicyHeaderFactory() {} | ||
|
|
||
| public String getOption() { | ||
| return this.option; | ||
| } | ||
|
|
||
| public void setOption(String option) { | ||
| this.option = option; | ||
| } | ||
|
|
||
| @Override | ||
| protected Map<String, String> buildHeaders() { | ||
| return Collections.singletonMap(CROSS_ORIGIN_RESOURCE_POLICY_HEADER, this.option); | ||
| } | ||
|
Comment on lines
+21
to
+40
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,9 @@ | ||
| package org.openmetadata.service.governance.workflows; | ||
|
|
||
| import static org.openmetadata.schema.entity.events.SubscriptionDestination.SubscriptionType.GOVERNANCE_WORKFLOW_CHANGE_EVENT; | ||
| import static org.openmetadata.service.governance.workflows.Workflow.ENTITY_LIST_VARIABLE; | ||
| import static org.openmetadata.service.governance.workflows.Workflow.GLOBAL_NAMESPACE; | ||
| import static org.openmetadata.service.governance.workflows.Workflow.RECOGNIZER_FEEDBACK; | ||
| import static org.openmetadata.service.governance.workflows.Workflow.RELATED_ENTITY_VARIABLE; | ||
| import static org.openmetadata.service.governance.workflows.Workflow.TRIGGERING_OBJECT_ID_VARIABLE; | ||
| import static org.openmetadata.service.governance.workflows.Workflow.UPDATED_BY_VARIABLE; | ||
| import static org.openmetadata.service.governance.workflows.WorkflowVariableHandler.getNamespacedVariableName; | ||
|
|
@@ -229,9 +229,10 @@ public static Map<String, Object> defaultHandler(ChangeEvent event) { | |
| MessageParser.EntityLink entityLink = | ||
| new MessageParser.EntityLink(entityType, entityReference.getFullyQualifiedName()); | ||
|
|
||
| String entityLinkString = entityLink.getLinkString(); | ||
| variables.put( | ||
| getNamespacedVariableName(GLOBAL_NAMESPACE, RELATED_ENTITY_VARIABLE), | ||
| entityLink.getLinkString()); | ||
| getNamespacedVariableName(GLOBAL_NAMESPACE, ENTITY_LIST_VARIABLE), | ||
| List.of(entityLinkString)); | ||
|
|
||
|
Comment on lines
+232
to
236
|
||
| // Set the updatedBy variable from the change event userName | ||
| if (event.getUserName() != null) { | ||
|
|
@@ -257,9 +258,10 @@ private static Map<String, Object> handleTagRecognizerFeedback(ChangeEvent event | |
| MessageParser.EntityLink entityLink = | ||
| new MessageParser.EntityLink(Entity.TAG, entityReference.getFullyQualifiedName()); | ||
|
|
||
| String entityLinkString = entityLink.getLinkString(); | ||
| variables.put( | ||
| getNamespacedVariableName(GLOBAL_NAMESPACE, RELATED_ENTITY_VARIABLE), | ||
| entityLink.getLinkString()); | ||
| getNamespacedVariableName(GLOBAL_NAMESPACE, ENTITY_LIST_VARIABLE), | ||
| List.of(entityLinkString)); | ||
|
|
||
| variables.put( | ||
| getNamespacedVariableName(GLOBAL_NAMESPACE, TRIGGERING_OBJECT_ID_VARIABLE), | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Entity.getEntitiesByLinks(...)parses all link strings without any per-item error handling and assumes all links share the same entity type (taken from the first link). A single malformed link string (or a mixed-type list) will throw during parse and fail the entire batch, which undermines the PR's goal of per-entity isolation. Consider: (1) catching parse exceptions per link and skipping/recording failures, and (2) validating that all links share the sameentityType(or grouping by type) with a clear error message.