-
Notifications
You must be signed in to change notification settings - Fork 207
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
Implementation of conditional routing of sinks #1832
Implementation of conditional routing of sinks #1832
Conversation
8756767
to
a878b30
Compare
Signed-off-by: David Venable <[email protected]>
Signed-off-by: David Venable <[email protected]>
af8a123
to
fac39ba
Compare
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.
Works great! I was also able to run a small test with routes
set on a pipeline connector.
A few small things below:
return new DataFlowComponent<>(sink, pluginSetting.getRoutes()); | ||
} | ||
|
||
private Sink buildSinkOrConnector(final PluginSetting pluginSetting) { | ||
// TODO: This will return an object which can perform routing. |
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.
Does this TODO item refer to the method defined around Line 249 and thus can be resolved?
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.
Yes, that is correct. Thanks for noting this, and I will remove.
} | ||
|
||
@Test | ||
void getComponent_returns_input_routes() { |
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.
nit:
void getComponent_returns_input_routes() { | |
void getRoutes_returns_input_routes() { |
} | ||
|
||
@Test | ||
void getComponent_returns_input_routes_when_empty() { |
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.
Same here:
void getComponent_returns_input_routes_when_empty() { | |
void getRoutes_returns_input_routes_when_empty() { |
void parseConfiguration_with_routes_creates_correct_pipeline() { | ||
mockDataPrepperConfigurationAccesses(); | ||
final PipelineParser pipelineParser = | ||
createObjectUnderTest("src/test/resources/valid_multiple_sinks.yml"); |
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.
Pipeline filename should be valid_multiple_sinks_with_routes.yml
.
…cted test names, correct test file. Signed-off-by: David Venable <[email protected]>
if(data instanceof Event) { | ||
|
||
final Event event = (Event) data; | ||
|
||
recordsToRoutes.put(record, new HashSet<>()); | ||
|
||
for (ConditionalRoute route : routes) { | ||
Boolean routed; | ||
try { | ||
routed = evaluator.evaluate(route.getCondition(), event); | ||
} catch (final Exception ex) { | ||
routed = false; | ||
LOG.error("Failed to evaluate route. This route will not be applied to any events.", ex); | ||
} | ||
if (routed) { | ||
recordsToRoutes | ||
.get(record) | ||
.add(route.getName()); | ||
} | ||
} | ||
} else { | ||
nonEventRecords++; | ||
recordsToRoutes.put(record, Collections.emptySet()); | ||
} |
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.
This can be simplified by breaking this down. This would also eliminate variable re-assignment and reads better:
if(data instanceof Event) {
final Event event = (Event) data;
final Set<String> matchedRoutes = findMatchedRoutes(event);
recordsToRoutes.put(record, matchedRoutes);
} else {
nonEventRecords++;
recordsToRoutes.put(record, Collections.emptySet());
}
...
private Set<String> findMatchedRoutes(final Event event) {
final Set<String> matchRoutes = new HashSet();
for (ConditionalRoute route : routes) {
try {
if (evaluator.evaluate(route.getCondition(), event)) {
matchRoutes.add(route.getName());
}
} catch (final Exception ex) {
LOG.error("Failed to evaluate route. This route will not be applied to any events.", ex);
}
return matchRoutes;
}
final Set<String> routesForEvent = recordsToRoutes | ||
.getOrDefault(event, Collections.emptySet()); | ||
|
||
boolean routed = false; | ||
for (String route : dataFlowComponent.getRoutes()) { | ||
if (routesForEvent.contains(route)) { | ||
routed = true; | ||
break; | ||
} | ||
} | ||
|
||
if (routed) { | ||
recordsForComponent.add(event); | ||
} |
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.
This can be simplified to eliminate the break
. This should still short circuit and not loop through every item if a match occurs.
final Set<String> routesForEvent = recordsToRoutes
.getOrDefault(event, Collections.emptySet());
final Set<String> dataFlowComponentRoutes = dataFlowComponent.getRoutes();
if (routesForEvent.stream().anyMatch(dataFlowComponentRoutes::contains)) {
recordsForComponent.add(event);
}
Signed-off-by: David Venable <[email protected]>
Description
This PR implements conditional routing.
I've rebased this PR to include #1840 and now it works with multiple processor threads.
Note that this only works for single-threaded pipelines due to #1189.Issues Resolved
Resolves #1337
Testing Information
Sample Pipeline:
File Input Source:
Run with Docker:
Results:
Check List
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.