Skip to content

Adding work item filters support#275

Open
bachuv wants to merge 1 commit intomainfrom
vabachu/work-item-filters
Open

Adding work item filters support#275
bachuv wants to merge 1 commit intomainfrom
vabachu/work-item-filters

Conversation

@bachuv
Copy link
Copy Markdown
Contributor

@bachuv bachuv commented Mar 27, 2026

Issue describing the changes in this PR

Adding work items filter support for the Java SDK.

resolves #issue_for_this_pr

Pull request checklist

  • My changes do not require documentation changes
    • Otherwise: Documentation issue linked to PR
  • My changes are added to the CHANGELOG.md
  • I have added all required tests (Unit tests, E2E tests)

@bachuv bachuv requested a review from a team as a code owner March 27, 2026 16:35
Copilot AI review requested due to automatic review settings March 27, 2026 16:35
*
* @return an unmodifiable list of activity filters
*/
public List<ActivityFilter> getActivities() {
*
* @return an unmodifiable list of orchestration filters
*/
public List<OrchestrationFilter> getOrchestrations() {
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

Adds work-item filtering support to the Java SDK worker so the backend can dispatch only matching orchestration/activity work items to a given DurableTaskGrpcWorker, with builder APIs for explicit or auto-generated filters.

Changes:

  • Introduces WorkItemFilter model + builder for orchestration/activity name (+ optional version) filters.
  • Extends DurableTaskGrpcWorkerBuilder to accept explicit filters or auto-generate filters from registered task types (with versioning-aware behavior for STRICT matching).
  • Updates DurableTaskGrpcWorker to send WorkItemFilters in GetWorkItemsRequest and adds unit tests + changelog entry.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
client/src/main/java/com/microsoft/durabletask/WorkItemFilter.java New public API type representing orchestration/activity work-item filters.
client/src/main/java/com/microsoft/durabletask/DurableTaskGrpcWorkerBuilder.java Adds useWorkItemFilters(...) APIs and auto-generation of filters during build().
client/src/main/java/com/microsoft/durabletask/DurableTaskGrpcWorker.java Sends filters to the sidecar via GetWorkItemsRequest.workItemFilters.
client/src/test/java/com/microsoft/durabletask/WorkItemFilterTest.java Unit tests for WorkItemFilter behavior + proto conversion.
client/src/test/java/com/microsoft/durabletask/WorkItemFilterBuilderTest.java Unit tests for builder/worker integration of explicit and auto-generated filters.
CHANGELOG.md Notes new work item filtering support in Unreleased.

Comment on lines +421 to +424
private GetWorkItemsRequest buildGetWorkItemsRequest() {
GetWorkItemsRequest.Builder builder = GetWorkItemsRequest.newBuilder();
if (this.workItemFilter != null) {
builder.setWorkItemFilters(toProtoWorkItemFilters(this.workItemFilter));
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

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

buildGetWorkItemsRequest() rebuilds and re-serializes the WorkItemFilters proto every time the listen loop restarts (and could do so repeatedly on transient disconnects). Since workItemFilter is immutable for the lifetime of the worker, consider precomputing and storing the proto WorkItemFilters once (e.g., in the constructor) to reduce allocations and CPU in retry loops.

Suggested change
private GetWorkItemsRequest buildGetWorkItemsRequest() {
GetWorkItemsRequest.Builder builder = GetWorkItemsRequest.newBuilder();
if (this.workItemFilter != null) {
builder.setWorkItemFilters(toProtoWorkItemFilters(this.workItemFilter));
/**
* Cached proto representation of {@link #workItemFilter} to avoid rebuilding it on every retry.
* This is lazily initialized since {@code workItemFilter} is immutable for the lifetime of the worker.
*/
private volatile WorkItemFilters cachedWorkItemFilters;
private GetWorkItemsRequest buildGetWorkItemsRequest() {
GetWorkItemsRequest.Builder builder = GetWorkItemsRequest.newBuilder();
if (this.workItemFilter != null) {
// Lazily compute and cache the proto WorkItemFilters since workItemFilter is immutable
WorkItemFilters filters = this.cachedWorkItemFilters;
if (filters == null) {
synchronized (this) {
filters = this.cachedWorkItemFilters;
if (filters == null) {
filters = toProtoWorkItemFilters(this.workItemFilter);
this.cachedWorkItemFilters = filters;
}
}
}
builder.setWorkItemFilters(filters);

Copilot uses AI. Check for mistakes.
Comment on lines +95 to +97
List<String> versionsCopy = versions != null
? Collections.unmodifiableList(new ArrayList<String>(versions))
: Collections.<String>emptyList();
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

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

addOrchestration(name, versions) copies the provided versions list but doesn't validate its contents. If versions contains any null elements, toProtoWorkItemFilters will later fail when calling addAllVersions(...) on the protobuf builder (protobuf repeated string fields don't accept null entries). Consider rejecting null version entries (and optionally empty strings) up-front with an IllegalArgumentException.

Suggested change
List<String> versionsCopy = versions != null
? Collections.unmodifiableList(new ArrayList<String>(versions))
: Collections.<String>emptyList();
List<String> versionsCopy;
if (versions == null) {
versionsCopy = Collections.<String>emptyList();
} else {
List<String> cleanedVersions = new ArrayList<String>(versions.size());
for (String version : versions) {
if (version == null || version.isEmpty()) {
throw new IllegalArgumentException("Orchestration filter versions must not contain null or empty entries.");
}
cleanedVersions.add(version);
}
versionsCopy = Collections.unmodifiableList(cleanedVersions);
}

Copilot uses AI. Check for mistakes.
Comment on lines +123 to +131
public Builder addActivity(String name, List<String> versions) {
if (name == null || name.isEmpty()) {
throw new IllegalArgumentException("Activity filter name must not be null or empty.");
}
List<String> versionsCopy = versions != null
? Collections.unmodifiableList(new ArrayList<String>(versions))
: Collections.<String>emptyList();
this.activities.add(new ActivityFilter(name, versionsCopy));
return this;
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

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

addActivity(name, versions) doesn't validate the contents of the versions list. If callers pass a list containing null elements, proto conversion via addAllVersions(...) will throw at runtime. Add input validation to reject null entries (and optionally empty strings) before storing the filter.

Copilot uses AI. Check for mistakes.
Comment on lines +190 to +196
WorkItemFilter.Builder builder = WorkItemFilter.newBuilder();
for (String name : this.orchestrationFactories.keySet()) {
builder.addOrchestration(name, versions);
}
for (String name : this.activityFactories.keySet()) {
builder.addActivity(name, versions);
}
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

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

buildAutoWorkItemFilter() iterates over HashMap.keySet(), which has undefined iteration order. This makes the generated filter list ordering nondeterministic, which can complicate debugging/tests and can cause unnecessary request churn if the backend treats ordering as significant. Consider iterating over a sorted list of keys (e.g., copy + Collections.sort) to produce a stable order.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants