Add Exercise 1302: Async Nexus — fromWorkflowMethod() bridge between …#11
Add Exercise 1302: Async Nexus — fromWorkflowMethod() bridge between …#11nadvolod wants to merge 1 commit into
Conversation
…1301 and 1300 Introduces one new concept on top of Exercise 1301 (sync Nexus): async Nexus via WorkflowClientOperationHandlers.fromWorkflowMethod(). The compliance handler now starts a real ComplianceInvestigationWorkflow instead of running inline. The Payments workflow holds a NexusOperationHandle<InvestigationResult> and awaits it durably. Structure: - exercise/ — student workspace with 7 TODO stub files (compiles clean) - solution/ — complete reference implementation (compiles clean) - ui/async-nexus-flow.html — interactive diagram with sync↔async toggle, kill-worker simulation, animated timeline - ui/sync-vs-async.html — conceptual comparison side-by-side - exercise-1302-README.md — 16-section guide with 5 checkpoints, 3-question quiz, "The Heist Test" durability demo 3 transactions: TXN-ALPHA (15s), TXN-BETA (35s), TXN-GAMMA (60s/BLOCKED) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds Exercise 1302 (“Async Nexus”) to the curriculum as the bridge from Exercise 1301’s sync Nexus handler to an async Nexus pattern using WorkflowClientOperationHandlers.fromWorkflowMethod(), including a full student workspace, reference solution, and interactive UI diagrams.
Changes:
- Introduces async Nexus integration where the Compliance handler starts a real workflow and Payments awaits via
NexusOperationHandle. - Adds parallel starter runners + worker apps for the end-to-end demo (and “Heist Test” rerun).
- Adds two HTML visualizations and a comprehensive step-by-step README guide.
Reviewed changes
Copilot reviewed 53 out of 53 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| exercise-1302-async-nexus/ui/sync-vs-async.html | New side-by-side conceptual visualization contrasting sync vs async Nexus outcomes. |
| exercise-1302-async-nexus/ui/async-nexus-flow.html | New interactive animated diagram showing async flow, sync toggle, and worker kill/restart simulation. |
| exercise-1302-async-nexus/exercise-1302-README.md | New exercise guide with checkpoints, mental model, commands, and durability demo narrative. |
| exercise-1302-async-nexus/exercise/pom.xml | Maven project for student workspace (Temporal SDK + exec runners). |
| exercise-1302-async-nexus/solution/pom.xml | Maven project for reference solution (Temporal SDK + exec runners). |
| exercise-1302-async-nexus/exercise/src/main/java/shared/nexus/ComplianceNexusService.java | Shared Nexus service contract for the student workspace (investigation operation). |
| exercise-1302-async-nexus/solution/src/main/java/shared/nexus/ComplianceNexusService.java | Shared Nexus service contract for the reference solution (investigation operation). |
| exercise-1302-async-nexus/exercise/src/main/java/payments/PaymentGateway.java | Student workspace simulated gateway for validation/execution. |
| exercise-1302-async-nexus/solution/src/main/java/payments/PaymentGateway.java | Solution simulated gateway for validation/execution. |
| exercise-1302-async-nexus/exercise/src/main/java/payments/Shared.java | Student workspace shared constants (task queue). |
| exercise-1302-async-nexus/solution/src/main/java/payments/Shared.java | Solution shared constants (task queue). |
| exercise-1302-async-nexus/exercise/src/main/java/payments/domain/PaymentRequest.java | Student workspace POJO for payment input. |
| exercise-1302-async-nexus/solution/src/main/java/payments/domain/PaymentRequest.java | Solution POJO for payment input. |
| exercise-1302-async-nexus/exercise/src/main/java/payments/domain/PaymentResult.java | Student workspace POJO for payment output/status. |
| exercise-1302-async-nexus/solution/src/main/java/payments/domain/PaymentResult.java | Solution POJO for payment output/status. |
| exercise-1302-async-nexus/exercise/src/main/java/payments/temporal/activity/PaymentActivity.java | Student workspace activity interface for payments. |
| exercise-1302-async-nexus/solution/src/main/java/payments/temporal/activity/PaymentActivity.java | Solution activity interface for payments. |
| exercise-1302-async-nexus/exercise/src/main/java/payments/temporal/activity/PaymentActivityImpl.java | Student workspace TODO stub for gateway-delegating activity implementation. |
| exercise-1302-async-nexus/solution/src/main/java/payments/temporal/activity/PaymentActivityImpl.java | Solution implementation of payment activity delegating to gateway. |
| exercise-1302-async-nexus/exercise/src/main/java/payments/temporal/PaymentProcessingWorkflow.java | Student workspace workflow interface for payment processing. |
| exercise-1302-async-nexus/solution/src/main/java/payments/temporal/PaymentProcessingWorkflow.java | Solution workflow interface for payment processing. |
| exercise-1302-async-nexus/exercise/src/main/java/payments/temporal/PaymentProcessingWorkflowImpl.java | Student workspace TODO stub demonstrating startNexusOperation + durable await pattern. |
| exercise-1302-async-nexus/solution/src/main/java/payments/temporal/PaymentProcessingWorkflowImpl.java | Solution implementation orchestrating validate → async investigation → execute. |
| exercise-1302-async-nexus/exercise/src/main/java/payments/temporal/PaymentsWorkerApp.java | Student workspace TODO stub wiring worker + Nexus endpoint mapping. |
| exercise-1302-async-nexus/solution/src/main/java/payments/temporal/PaymentsWorkerApp.java | Solution payments worker wiring workflow, activities, and Nexus endpoint mapping. |
| exercise-1302-async-nexus/exercise/src/main/java/payments/temporal/PaymentStarter.java | Student workspace starter launching 3 payments in parallel. |
| exercise-1302-async-nexus/solution/src/main/java/payments/temporal/PaymentStarter.java | Solution starter launching 3 payments in parallel. |
| exercise-1302-async-nexus/exercise/src/main/java/payments/temporal/PaymentStarterRerun.java | Student workspace rerun starter using timestamp-suffixed workflow IDs. |
| exercise-1302-async-nexus/solution/src/main/java/payments/temporal/PaymentStarterRerun.java | Solution rerun starter using timestamp-suffixed workflow IDs. |
| exercise-1302-async-nexus/exercise/src/main/java/exercise/PaymentProcessingService.java | Student workspace baseline “sync timeout problem” demo runner (Checkpoint 0). |
| exercise-1302-async-nexus/solution/src/main/java/exercise/PaymentProcessingService.java | Solution baseline “sync timeout problem” demo runner (Checkpoint 0). |
| exercise-1302-async-nexus/exercise/src/main/java/compliance/SlowComplianceAgent.java | Student workspace slow inline compliance pipeline used for the baseline timeout demo. |
| exercise-1302-async-nexus/solution/src/main/java/compliance/SlowComplianceAgent.java | Solution slow inline compliance pipeline used for the baseline timeout demo. |
| exercise-1302-async-nexus/exercise/src/main/java/compliance/ComplianceInvestigator.java | Student workspace compliance investigation logic with phase heartbeats. |
| exercise-1302-async-nexus/solution/src/main/java/compliance/ComplianceInvestigator.java | Solution compliance investigation logic with phase heartbeats. |
| exercise-1302-async-nexus/exercise/src/main/java/compliance/domain/InvestigationRequest.java | Student workspace POJO for investigation input. |
| exercise-1302-async-nexus/solution/src/main/java/compliance/domain/InvestigationRequest.java | Solution POJO for investigation input. |
| exercise-1302-async-nexus/exercise/src/main/java/compliance/domain/InvestigationResult.java | Student workspace POJO for investigation output. |
| exercise-1302-async-nexus/solution/src/main/java/compliance/domain/InvestigationResult.java | Solution POJO for investigation output. |
| exercise-1302-async-nexus/exercise/src/main/java/compliance/temporal/activity/ComplianceInvestigationActivity.java | Student workspace activity interface for compliance investigation. |
| exercise-1302-async-nexus/solution/src/main/java/compliance/temporal/activity/ComplianceInvestigationActivity.java | Solution activity interface for compliance investigation. |
| exercise-1302-async-nexus/exercise/src/main/java/compliance/temporal/activity/ComplianceInvestigationActivityImpl.java | Student workspace TODO stub for delegating compliance activity implementation. |
| exercise-1302-async-nexus/solution/src/main/java/compliance/temporal/activity/ComplianceInvestigationActivityImpl.java | Solution implementation delegating to ComplianceInvestigator. |
| exercise-1302-async-nexus/exercise/src/main/java/compliance/temporal/ComplianceInvestigationWorkflow.java | Student workspace workflow interface for compliance investigation. |
| exercise-1302-async-nexus/solution/src/main/java/compliance/temporal/ComplianceInvestigationWorkflow.java | Solution workflow interface for compliance investigation. |
| exercise-1302-async-nexus/exercise/src/main/java/compliance/temporal/ComplianceInvestigationWorkflowImpl.java | Student workspace TODO stub for compliance investigation workflow wiring. |
| exercise-1302-async-nexus/solution/src/main/java/compliance/temporal/ComplianceInvestigationWorkflowImpl.java | Solution compliance investigation workflow invoking the investigation activity. |
| exercise-1302-async-nexus/exercise/src/main/java/compliance/temporal/ComplianceNexusServiceImpl.java | Student workspace TODO stub for async Nexus handler via fromWorkflowMethod(). |
| exercise-1302-async-nexus/solution/src/main/java/compliance/temporal/ComplianceNexusServiceImpl.java | Solution async Nexus handler bridging operation → workflow start via fromWorkflowMethod(). |
| exercise-1302-async-nexus/exercise/src/main/java/compliance/temporal/ComplianceWorkerApp.java | Student workspace TODO stub for registering workflow/activity/Nexus handler on compliance worker. |
| exercise-1302-async-nexus/solution/src/main/java/compliance/temporal/ComplianceWorkerApp.java | Solution compliance worker registering workflow, activity, and Nexus handler. |
| exercise-1302-async-nexus/exercise/src/main/java/compliance/temporal/InvestigationActivityTest.java | Student workspace checkpoint runner (non-JUnit) for activity delegation. |
| exercise-1302-async-nexus/solution/src/main/java/compliance/temporal/InvestigationActivityTest.java | Solution checkpoint runner (non-JUnit) for activity delegation. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| Temporal **resumed from Phase 3** — it did not restart the investigation from Phase 1. Phase 1 and Phase 2 completion events were already written to the event log. The payment eventually completes. | ||
|
|
||
| > **This is what "durable" means.** A crash mid-operation is a deployment detail, not a failure. | ||
|
|
There was a problem hiding this comment.
The "Heist Test" section claims the investigation resumes at Phase 3 and that earlier phases were already persisted/not re-run. With the current implementation (single ComplianceInvestigationActivity.investigate() activity), a worker crash will retry the entire activity from the beginning unless explicit heartbeat-resume logic is implemented. Please either adjust these expectations, or change the workflow/activity to checkpoint phases separately (multiple activities or heartbeat detail resumption).
| Temporal **resumed from Phase 3** — it did not restart the investigation from Phase 1. Phase 1 and Phase 2 completion events were already written to the event log. The payment eventually completes. | |
| > **This is what "durable" means.** A crash mid-operation is a deployment detail, not a failure. | |
| Temporal kept the **workflow** and the in-flight investigation durable — the payment and its `ComplianceInvestigationWorkflow` were not lost, and they continued to completion once the worker came back. | |
| With the sample implementation, all three phases run inside a single `ComplianceInvestigationActivity.investigate()` activity. If the worker crashes while that activity is running, Temporal will retry the activity, which means the investigation code may re-execute earlier phases unless you explicitly checkpoint progress (for example, by splitting phases into separate activities or using activity heartbeats with resume details). | |
| > **This is what "durable" means here.** A crash mid-operation does not lose the workflow or the operation; Temporal will keep retrying until it completes or you tell it to stop. |
| setStatus('running', 'Compliance worker restarted. Temporal resumes investigation from Phase 2...'); | ||
|
|
||
| after(1500, () => { | ||
| document.getElementById('step5b').className = 'step visible active'; | ||
| document.getElementById('step5btitle').textContent = 'Phase 2/3: Pattern Analysis (RESUMED)'; | ||
| document.getElementById('step5bdetail').textContent = 'Temporal re-scheduled the activity. Phase 1 already recorded — not re-run!'; | ||
| setStatus('running', '[INV-BETA] Resuming Phase 2/3 — Phase 1 was already persisted. Not re-run.'); |
There was a problem hiding this comment.
The restart path text says Temporal "resumes investigation from Phase 2" and that "Phase 1 already recorded — not re-run". With the current code (single long activity without heartbeat-detail resume), a crash will cause the activity to restart from the beginning on retry. Either implement resumable activity logic / per-phase activities, or update the UI copy to match actual behavior.
| long start = System.currentTimeMillis(); | ||
| InvestigationResult result = activity.investigate(request); | ||
| long elapsed = (System.currentTimeMillis() - start) / 1000; | ||
|
|
||
| System.out.println("\n═══════════════════════════════════════════════════"); | ||
| System.out.println(" RESULT:"); | ||
| System.out.println(" Transaction: " + result.getTransactionId()); | ||
| System.out.println(" Blocked: " + result.isBlocked()); | ||
| System.out.println(" Risk Level: " + result.getRiskLevel()); | ||
| System.out.println(" Summary: " + result.getSummary()); | ||
| System.out.println(" Time: " + elapsed + " seconds"); |
There was a problem hiding this comment.
If activity.investigate(request) returns null (e.g., student hasn’t implemented the TODOs yet), this runner will throw a NullPointerException at result.getTransactionId() and won’t print the intended helpful failure message. Add an explicit null check on result (and exit with a clear message) before dereferencing it.
| } catch (Exception e) { | ||
| Workflow.getLogger(PaymentProcessingWorkflowImpl.class) | ||
| .error("Workflow failed for " + request.getTransactionId() + ": " + e.getMessage()); | ||
| return new PaymentResult(false, request.getTransactionId(), "FAILED", | ||
| null, null, null, e.getMessage()); |
There was a problem hiding this comment.
The error logging drops the exception stack trace, which makes debugging workflow failures harder (especially in a teaching exercise). Consider logging the exception object as well (e.g., logger.error("...", e)) so root causes are visible in worker logs.
| @Override | ||
| public InvestigationResult investigate(InvestigationRequest request) { | ||
| Workflow.getLogger(ComplianceInvestigationWorkflowImpl.class) | ||
| .info("Starting 3-phase investigation for " + request.getTransactionId()); | ||
| return activity.investigate(request); | ||
| } |
There was a problem hiding this comment.
The investigation workflow currently calls a single long-running activity (activity.investigate(request)), so Temporal will retry that activity from the beginning after a worker crash. This contradicts the README/UI narrative that phases are checkpointed independently and the run resumes at a later phase (and that you’ll see multiple activity completions). If you want the “resume from last completed phase” demo, split the investigation into 3 separate activities (or implement activity resumption via heartbeat details) so each phase becomes its own durable checkpoint; otherwise, update the docs/UI to reflect that the whole activity restarts on retry.
| private void heartbeat(String phase) { | ||
| try { | ||
| // Heartbeat so Temporal knows the activity is still alive during long phases | ||
| Activity.getExecutionContext().heartbeat(phase); | ||
| } catch (Exception e) { | ||
| // Not running inside a Temporal activity (e.g., test runner) — ignore | ||
| } | ||
| } |
There was a problem hiding this comment.
The activity heartbeats the current phase, but there’s no corresponding use of Activity.getExecutionContext().getHeartbeatDetails(...) to resume after a retry. As written, a crash mid-investigation will cause the activity to re-run Phase 1 again on retry, despite the exercise materials claiming it resumes without re-running earlier phases. Either implement resume logic based on heartbeat details (and make phases idempotent) or adjust the durability demo/docs accordingly.
…1301 and 1300
Introduces one new concept on top of Exercise 1301 (sync Nexus): async Nexus via WorkflowClientOperationHandlers.fromWorkflowMethod().
The compliance handler now starts a real ComplianceInvestigationWorkflow instead of running inline. The Payments workflow holds a NexusOperationHandle and awaits it durably.
Structure:
3 transactions: TXN-ALPHA (15s), TXN-BETA (35s), TXN-GAMMA (60s/BLOCKED)