Skip to content

fix(tasks): emit change events on Task resolve/close/applySuggestion - #28140

Closed
sonika-shah wants to merge 1 commit into
mainfrom
fix/task-lifecycle-change-events
Closed

fix(tasks): emit change events on Task resolve/close/applySuggestion#28140
sonika-shah wants to merge 1 commit into
mainfrom
fix/task-lifecycle-change-events

Conversation

@sonika-shah

Copy link
Copy Markdown
Collaborator

Problem

TaskResource.resolveTask (POST /api/v1/tasks/{id}/resolve), closeTask (POST /api/v1/tasks/{id}/close), and applySuggestion (POST /api/v1/tasks/{id}/applySuggestion) all returned Response.ok(resolvedTask).build() with no X-OpenMetadata-Change header. The JAX-RS response filter ChangeEventHandler only emits a ChangeEvent when that header is present (or when the status is CREATED), so:

  • No row appeared in change_event for resolve/close turnarounds.
  • EventSubscriptions on resource: task + filterByEventType: [taskResolved, taskClosed] could never fire — empty Recent Events, no email, no webhook.
  • The semantically most meaningful Task transitions were invisible to audit, alerts, and downstream consumers.

This regression was introduced by the Task System Redesign (#25894), which moved Task from a Thread sub-type to a first-class entity. The legacy /v1/feed/tasks/{id}/resolve|close routes still emit TASK_RESOLVED / TASK_CLOSED via FeedRepository, but the new TaskResource endpoints did not.

Fix

Set CHANGE_CUSTOM_HEADER on the three affected responses:

Endpoint Event emitted
POST /v1/tasks/{id}/resolve taskResolved
POST /v1/tasks/{id}/close taskClosed
POST /v1/tasks/{id}/applySuggestion taskResolved

FormatterUtil.createChangeEventForEntity then builds a ChangeEvent with entityType="task" and entity=<Task>, which ChangeEventHandler persists and forwards to EventSubscription consumers — restoring parity with the legacy route and the eventType values already declared in changeEventType.json.

Tests

Two new integration tests in TaskResourceIT:

  • testResolveTaskEmitsTaskResolvedChangeEventHeader — asserts X-OpenMetadata-Change: taskResolved on /resolve.
  • testCloseTaskEmitsTaskClosedChangeEventHeader — asserts X-OpenMetadata-Change: taskClosed on /close.

Both use a direct java.net.http.HttpClient call (the SDK's HttpClient doesn't expose response headers). Tests use TestNamespace for isolation and run safely under @Execution(ExecutionMode.CONCURRENT).

applySuggestion follows the same one-line pattern; given the same FormatterUtil machinery handles all three identically, a focused header test on resolve+close is sufficient to prove the wiring. A future PR can extend coverage when Suggestion-task setup helpers are needed for unrelated reasons.

Scope

Related to #27889 (do not auto-close — three other problems remain). This PR addresses only the missing change-event emission for resolve / close / applySuggestion on the new TaskResource.

Out of scope — needs separate work / design call

  1. Bulk operations endpoint (POST /v1/tasks/bulk) processes multiple tasks in one HTTP request. The single-valued X-OpenMetadata-Change header can't express N events; fixing this needs per-task event emission from inside TaskWorkflowHandler rather than via the response filter. Tracked separately.

  2. Orphan taskCreated / taskUpdated EventType values are declared in changeEventType.json but emitted nowhere in openmetadata-service. The new TaskResource emits entityCreated / entityUpdated like every other entity. Needs a design call: drop from the enum, or have TaskResource emit TASK_CREATED / TASK_UPDATED instead.

  3. UI alert builder (AlertsUtil.tsx) still populates filterByEventType from the entire EventType enum regardless of selected resource. Users can continue to save unreachable combinations. Depends on the outcome of (2) before the resource→eventTypes mapping can be defined.

`TaskResource.resolveTask`, `closeTask`, and `applySuggestion` returned
`Response.ok(...).build()` without `X-OpenMetadata-Change`, so the
`ChangeEventHandler` response filter produced no change event for task
lifecycle transitions. Subscriptions on `task + taskResolved` /
`taskClosed` could never fire; the audit log carried no row for
resolve/close turnarounds.

Setting `CHANGE_CUSTOM_HEADER` to `TASK_RESOLVED` / `TASK_CLOSED` on
these three responses restores parity with the legacy
`/v1/feed/tasks/{id}/resolve|close` routes (which emit the same event
types from `FeedRepository`) and unblocks the alert combinations that
were silently dropped after the Task System Redesign (#25894).

Related to #27889 — this is one of three remaining problems documented
in that issue; the bulk operations endpoint, orphan
`taskCreated` / `taskUpdated` `EventType` values, and the UI alert
builder offering unmatchable resource+eventType combinations need
separate follow-ups and a design decision.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Restores change-event emission for the new TaskResource endpoints /resolve, /close, and /applySuggestion by setting the X-OpenMetadata-Change response header so ChangeEventHandler produces taskResolved / taskClosed events. This re-enables EventSubscriptions and audit-log entries for the most semantically important Task transitions, regressed by the Task System Redesign (#25894).

Changes:

  • Add CHANGE_CUSTOM_HEADER with TASK_RESOLVED/TASK_CLOSED to the three endpoint responses.
  • Add two integration tests asserting the response header is set on resolve/close.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
openmetadata-service/.../tasks/TaskResource.java Sets X-OpenMetadata-Change header on resolve/close/applySuggestion responses
openmetadata-integration-tests/.../TaskResourceIT.java New tests verifying the header is emitted; adds a small direct-HTTP helper

? HttpRequest.BodyPublishers.noBody()
: HttpRequest.BodyPublishers.ofString(body);
HttpRequest request = builder.method(method, publisher).build();
return java.net.http.HttpClient.newHttpClient()

@gitar-bot gitar-bot Bot May 15, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Quality: Test uses fully-qualified class name instead of import

In the sendDirectJson helper at line 3795, java.net.http.HttpClient.newHttpClient() is used as a fully-qualified name instead of importing java.net.http.HttpClient at the top of the file. The custom review instructions require no fully-qualified names in code. Since HttpRequest and HttpResponse from the same package are already imported, HttpClient should be imported as well.

Import HttpClient and use unqualified name:

// Add to imports at top of file:
import java.net.http.HttpClient;

// Then replace line 3795:
    return HttpClient.newHttpClient()
        .send(request, HttpResponse.BodyHandlers.ofString());

Was this helpful? React with 👍 / 👎

@gitar-bot

gitar-bot Bot commented May 15, 2026

Copy link
Copy Markdown
Code Review 👍 Approved with suggestions 0 resolved / 1 findings

Restores task lifecycle event emission by adding missing change headers to resolve, close, and applySuggestion endpoints. Update the test helper to use an import instead of the fully-qualified class name.

💡 Quality: Test uses fully-qualified class name instead of import

📄 openmetadata-integration-tests/src/test/java/org/openmetadata/it/tests/TaskResourceIT.java:3795

In the sendDirectJson helper at line 3795, java.net.http.HttpClient.newHttpClient() is used as a fully-qualified name instead of importing java.net.http.HttpClient at the top of the file. The custom review instructions require no fully-qualified names in code. Since HttpRequest and HttpResponse from the same package are already imported, HttpClient should be imported as well.

Import HttpClient and use unqualified name
// Add to imports at top of file:
import java.net.http.HttpClient;

// Then replace line 3795:
    return HttpClient.newHttpClient()
        .send(request, HttpResponse.BodyHandlers.ofString());
🤖 Prompt for agents
Code Review: Restores task lifecycle event emission by adding missing change headers to resolve, close, and applySuggestion endpoints. Update the test helper to use an import instead of the fully-qualified class name.

1. 💡 Quality: Test uses fully-qualified class name instead of import
   Files: openmetadata-integration-tests/src/test/java/org/openmetadata/it/tests/TaskResourceIT.java:3795

   In the `sendDirectJson` helper at line 3795, `java.net.http.HttpClient.newHttpClient()` is used as a fully-qualified name instead of importing `java.net.http.HttpClient` at the top of the file. The custom review instructions require no fully-qualified names in code. Since `HttpRequest` and `HttpResponse` from the same package are already imported, `HttpClient` should be imported as well.

   Fix (Import HttpClient and use unqualified name):
   // Add to imports at top of file:
   import java.net.http.HttpClient;
   
   // Then replace line 3795:
       return HttpClient.newHttpClient()
           .send(request, HttpResponse.BodyHandlers.ofString());

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

@github-actions

Copy link
Copy Markdown
Contributor

🟡 Playwright Results — all passed (15 flaky)

✅ 4065 passed · ❌ 0 failed · 🟡 15 flaky · ⏭️ 92 skipped

Shard Passed Failed Flaky Skipped
🟡 Shard 1 298 0 1 4
🟡 Shard 2 754 0 8 14
🟡 Shard 3 780 0 1 7
✅ Shard 4 790 0 0 18
🟡 Shard 5 707 0 2 41
🟡 Shard 6 736 0 3 8
🟡 15 flaky test(s) (passed on retry)
  • Pages/UserCreationWithPersona.spec.ts › Create user with persona and verify on profile (shard 1, 1 retry)
  • Features/BulkEditEntity.spec.ts › Glossary (shard 2, 1 retry)
  • Features/ColumnBulkOperations.spec.ts › should filter by entity type (Table) (shard 2, 1 retry)
  • Features/DataQuality/BundleSuiteBulkOperations.spec.ts › Create new Bundle Suite with bulk selected test cases (shard 2, 1 retry)
  • Features/IncidentManager.spec.ts › Next, Previous and page indicator (shard 2, 1 retry)
  • Features/KnowledgeCenterList.spec.ts › Knowledge Center List - Test infinite scroll/pagination (shard 2, 1 retry)
  • Features/KnowledgeCenterTextEditor.spec.ts › Rich Text Editor - Text Formatting (shard 2, 1 retry)
  • Features/KnowledgeCenterTextEditor.spec.ts › Rich Text Editor - Text Formatting (shard 2, 1 retry)
  • Features/KnowledgeCenterTextEditor.spec.ts › Rich Text Editor - Text Formatting (shard 2, 1 retry)
  • Features/RTL.spec.ts › Verify Following widget functionality (shard 3, 1 retry)
  • Pages/EntityDataSteward.spec.ts › Tier Add, Update and Remove (shard 5, 1 retry)
  • Pages/ExplorePageRightPanel_KnowledgeCenter.spec.ts › Should remove user owner for knowledgeCenter (shard 5, 1 retry)
  • Features/AutoPilot.spec.ts › Create Service and check the AutoPilot status (shard 6, 1 retry)
  • Pages/Glossary.spec.ts › Drag and Drop Glossary Term (shard 6, 1 retry)
  • Pages/Lineage/LineageFilters.spec.ts › Verify lineage schema filter selection (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

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