-
Notifications
You must be signed in to change notification settings - Fork 324
Nexus V2 Documentation - don't review or merge!! #5068
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
Open
Evanthx
wants to merge
16
commits into
main
Choose a base branch
from
nexus-v2
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
ce43323
Adding documentation for Nexus Client library code generation
Evanthx b65227a
Some proposed documentation. Do not merge, this is just for review.
Evanthx 1223ad1
Updating links
Evanthx 9d5c281
Updating docs
Evanthx bd55d8d
Unlisted the developer experience files
Evanthx f56c913
Updated code generation doc page
Evanthx ba4bc2a
Updating
Evanthx 85b4e51
Wording change
Evanthx 198ec75
IDL doc update
Evanthx 8b37b44
Renaming from V2, working on SAA doc
Evanthx 431a734
Working on operation handler doc
Evanthx 3ede7b0
Working on docs
Evanthx 02ebd7e
Update docs/encyclopedia/nexus/nexus.mdx
Evanthx 5cd245a
Update docs/encyclopedia/nexus/temporal-operation-handler.mdx
Evanthx 1a5acd9
Responding to PR comments
Evanthx 6005943
Updated walkthrough doc with sample Java code
Evanthx File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
72 changes: 72 additions & 0 deletions
72
docs/develop/java/nexus/development-walkthrough/add-a-standalone-activity.mdx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| --- | ||
| id: add-a-standalone-activity | ||
| title: Step 9 - Add a Standalone Activity | ||
| sidebar_label: 9. Add a Standalone Activity | ||
| description: Back the notification Nexus Operation with a Standalone Activity instead of a Workflow, with no wrapper Workflow required. | ||
| toc_max_heading_level: 4 | ||
| unlisted: true | ||
| tags: | ||
| - Nexus | ||
| - Java SDK | ||
| --- | ||
|
|
||
| The last Operation is `notifyRequester`, which tells the requester their approval was `APPROVED` or `DENIED`. | ||
|
|
||
| This one is not a Workflow. It is a single outbound notification with no state, nothing to wait for, and nothing to orchestrate — the [Standalone Activity](/nexus/standalone-activity) shape chosen in [step 3](/develop/java/nexus/development-walkthrough/choose-backing-implementation). | ||
|
|
||
| ## Write the Activity | ||
|
|
||
| The Activity is an ordinary Activity. In this walkthrough it is a placeholder that does nothing — no email is sent. Real logic would call an email provider, push to a notification service, or write to an outbox. | ||
|
|
||
| Nothing in it is Nexus-specific. The same Activity Function can be invoked from a Workflow and started behind this Operation with no code changes — what differs is what starts it, not how it is written. | ||
|
|
||
| <!--SNIPSTART samples-java-nexus-walkthrough-activities--> | ||
| <!--SNIPEND--> | ||
|
|
||
| ## Back the Operation with it | ||
|
|
||
| Use `TemporalOperationHandler` as with every other Operation, but start an Activity on the [Client](/nexus/temporal-operation-handler#the-nexus-aware-client) instead of a Workflow. The Operation starts an Activity Execution with no parent Workflow and completes when the Activity returns. | ||
|
|
||
| This is the right shape whenever an Operation is one durable step behind a team boundary. The Activity supplies the durability — retries on the policy you set, timeouts you control, and a record of every attempt — and the Operation supplies the contract, so the notification is reachable by other teams without them sharing your code or your Namespace. | ||
|
|
||
| <!--SNIPSTART samples-java-nexus-walkthrough-notify-requester--> | ||
| <!--SNIPEND--> | ||
|
|
||
| ### Options an Activity-backed Operation requires | ||
|
|
||
| `StartActivityOptions` needs an **Activity Id**, unique within the Namespace, which a Workflow-called Activity does not, because there is no parent Workflow to scope it. | ||
|
|
||
| The Task Queue is optional and defaults to the one the Operation is running on. Set it explicitly to run notifications on their own Worker fleet rather than the one the Endpoint targets. | ||
|
|
||
| **To keep server retries from sending a second email, derive the Activity Id from the Nexus request Id.** The server retries Nexus start requests, and the request Id travels with them, so every retry lands on the same Activity Id and the notification goes out once. Without that, a retried request is a duplicate message to a real person. | ||
|
|
||
| The same pattern applies to any Operation whose work is externally visible and cannot be taken back: charging a card, posting to a webhook, creating a ticket, writing to a system with no dedup of its own. Deriving the Id from the request Id costs nothing and removes the whole class of duplicate-side-effect bugs. | ||
|
|
||
| Deriving the Id from the Operation *input* instead is a different tool for a different job: it makes several Operations share one Activity Execution and all receive its result. See [Nexus Standalone Activity](/nexus/standalone-activity#required-options). | ||
|
|
||
| ## Register the Activity on the Worker | ||
|
|
||
| Add the Activity implementation to the same Worker that hosts the Nexus Service. An Activity-backed Operation needs no Workflow implementation registered for it. | ||
|
|
||
| <!--SNIPSTART samples-java-nexus-walkthrough-handler-worker--> | ||
| <!--SNIPEND--> | ||
|
|
||
| ## Cancellation needs heartbeating | ||
|
|
||
| This notification finishes immediately, so cancellation never comes up for it. It does come up for any longer Activity-backed Operation, and the behavior differs from a Workflow-backed one: an Activity is not interrupted by a cancellation request, so an Activity that never heartbeats runs to completion or to its timeout no matter how many cancellations arrive. | ||
|
|
||
| If you write a long-running Activity-backed Operation, read [Activity cancellation](/activity-execution#cancellation) before you ship it. None of the mechanics are Nexus-specific. | ||
|
|
||
| ## Next | ||
|
|
||
| **[Step 10 - Call the Standalone Activity](/develop/java/nexus/development-walkthrough/call-the-standalone-activity)** - complete the approval flow end to end. | ||
|
|
||
| Back to the [Microservice Development Walkthrough overview](/develop/java/nexus/development-walkthrough). | ||
|
|
||
| :::tip RESOURCES | ||
|
|
||
| - [Nexus Standalone Activity](/nexus/standalone-activity) for the full concept and options. | ||
| - [Standalone Activity](/standalone-activity) for Activity Executions outside a Workflow. | ||
| - [Java: Standalone Activities](/develop/java/activities/standalone-activities) for the SDK API. | ||
|
|
||
| ::: | ||
97 changes: 97 additions & 0 deletions
97
docs/develop/java/nexus/development-walkthrough/add-messaging.mdx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,97 @@ | ||
| --- | ||
| id: add-messaging | ||
| title: Step 7 - Add messaging | ||
| sidebar_label: 7. Add messaging | ||
| description: Expose a Signal and an Update on the approval Workflow as Nexus Operations using the Nexus-aware Client. | ||
| toc_max_heading_level: 4 | ||
| unlisted: true | ||
| tags: | ||
| - Nexus | ||
| - Java SDK | ||
| --- | ||
|
|
||
| The approval blocks waiting for a decision. **Messages** give callers a way to interact with it while it waits. | ||
|
|
||
| Two Operations get added to the workflow sample problem. Which [message](/sending-messages) type each one uses is decided by what the caller needs back, not by preference. | ||
|
|
||
| | Operation | Message type | Why this type | | ||
| | --- | --- | --- | | ||
| | `remindApprover` | Signal | Fire-and-forget. The caller does not need a response, only for the nudge to happen. | | ||
| | `submitDecision` | Update | Changes state *and* returns a result the caller needs — confirmation the decision was recorded. | | ||
|
|
||
| That is the whole rule. If the caller can proceed without hearing anything back, a Signal is enough. If the caller needs to know what the message did, it needs an Update. | ||
|
|
||
| ## Add the handlers to the Workflow | ||
|
|
||
| On the Workflow, add a Signal handler that increments the reminder count and an Update handler that records the decision and unblocks the wait. | ||
|
|
||
| The Update is what ends the approval. It records `APPROVED` or `DENIED`, which satisfies the condition the Workflow is blocked on, and the Workflow then returns that decision as its result. | ||
|
|
||
| <!--SNIPSTART samples-java-nexus-walkthrough-approval-workflow--> | ||
| <!--SNIPEND--> | ||
|
|
||
| ## Expose them as Nexus Operations | ||
|
|
||
| Both use `TemporalOperationHandler`, and they divide along the line described in [The Nexus-aware Client](/nexus/temporal-operation-handler#the-nexus-aware-client): a Signal is **sync messaging**, and an Update is an **async backing**. | ||
|
|
||
| ### Signal | ||
|
|
||
| Send the Signal through the Client, then return a synchronous result. The Operation completes immediately, during the handler call. | ||
|
|
||
| :::caution The handler has under 10 seconds | ||
|
|
||
| A synchronous handler must finish inside the [10-second handler deadline](/cloud/limits#nexus-operation-request-timeout), and the budget you actually get is smaller: the clock starts on the caller's side and the request still has to route through matching. | ||
|
|
||
| Sending one Signal is comfortably inside it. A handler that sends several messages, or does slow work before returning, is not. Overrunning gives the caller a context deadline exceeded error, which it then retries with exponential backoff until the schedule-to-close timeout expires. | ||
|
|
||
| ::: | ||
|
|
||
| <!--SNIPSTART samples-java-nexus-walkthrough-remind-approver--> | ||
| <!--SNIPEND--> | ||
|
|
||
| ### Update | ||
|
|
||
| Start the Update on the Client. This is an async backing: the Operation completes when the Update completes, and its result is delivered through the Nexus completion callback. If the Update happens to come back already complete — a retried request, or one that failed validation — the result returns synchronously instead. | ||
|
|
||
| An Update-backed Operation carries two requirements. It targets a Workflow that already exists, so a `submitDecision` for a purchase with no approval running fails. And because it is an async backing, there is at most one per Operation invocation, though a handler can still combine it with sync side effects. | ||
|
|
||
| ### Reject a bad Update before it changes anything | ||
|
|
||
| An Update can also refuse a request, which is the other thing a Signal cannot do. By the time a Signal handler runs the message has already been accepted and written to history; there is nowhere left to say no. | ||
|
|
||
| The approval uses that. A **validator** runs before the handler and rejects a second decision for an approval that has already been decided — without it, the later decision would silently overwrite the earlier one. A rejected Update never runs the handler, never reaches Event History, and surfaces to the caller as a failed Operation. | ||
|
|
||
| The validator is the method annotated `@UpdateValidatorMethod` in the Workflow interface above. It takes the same arguments as the handler, returns nothing, and must not change Workflow state. | ||
|
|
||
| <!--SNIPSTART samples-java-nexus-walkthrough-submit-decision--> | ||
| <!--SNIPEND--> | ||
|
|
||
| ## Do not poll for the decision | ||
|
|
||
| There is one design mistake worth naming, because it is the most common one in this shape: reaching for a message to fetch the final decision. | ||
|
|
||
| The decision is the result of `requestApproval`, and it reaches the caller without anyone asking for it. | ||
|
|
||
| When the handler started the approval, Nexus attached a [completion callback](/glossary#nexus-async-completion-callback) to that Workflow. The moment the Workflow returns, the handler's Namespace delivers the callback to the caller's Nexus Machinery, which records a `NexusOperationCompleted` event in the caller Workflow's history. The caller Worker picks that up on its next Workflow Task, and the caller Workflow resumes with the decision. See the [asynchronous Operation lifecycle](/nexus/operations#asynchronous-operation-lifecycle) for the full sequence. | ||
|
|
||
| A caller that instead asks the approval for its status in a loop is polling for something already on its way. | ||
|
|
||
| Messages are for changing a running approval or nudging it along, not for collecting its outcome. `remindApprover` asks the approver again. `submitDecision` supplies the decision and confirms it landed. Neither is a way to read the result. | ||
|
|
||
| Both also stop working the moment the approval completes. The Temporal Service accepts a Signal or an Update only while the Workflow is still running, and rejects one sent to a closed Workflow with `NOT_FOUND: workflow execution already completed`. That happens as soon as the decision lands, not when the [Retention Period](/temporal-service/temporal-server#retention-period) later expires and the Execution is deleted. A second `submitDecision` for an approval that has already been decided fails this way, and so does any attempt to use these Operations to look up a past decision. | ||
|
|
||
| If more than one system needs the outcome, see [step 8](/develop/java/nexus/development-walkthrough/send-messages#when-the-approval-already-exists) for how additional callers attach to a running approval and receive the same decision. | ||
|
|
||
| ## Next | ||
|
|
||
| **[Step 8 - Send messages](/develop/java/nexus/development-walkthrough/send-messages)** - call the messaging Operations, and handle an approval that may not exist yet. | ||
|
|
||
| Back to the [Microservice Development Walkthrough overview](/develop/java/nexus/development-walkthrough). | ||
|
|
||
| :::tip RESOURCES | ||
|
|
||
| - [Workflow message passing](/encyclopedia/workflow-message-passing) for Signals and Updates. | ||
| - [Handling messages](/handling-messages) for handler constraints. | ||
| - [Temporal Operation Handler](/nexus/temporal-operation-handler) for the sync messaging and async backing distinction. | ||
|
|
||
| ::: |
102 changes: 102 additions & 0 deletions
102
docs/develop/java/nexus/development-walkthrough/call-the-service.mdx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| --- | ||
| id: call-the-service | ||
| title: Step 6 - Call the Service | ||
| sidebar_label: 6. Call the Service | ||
| description: Call the approval Nexus Service from a caller Workflow in another Namespace, using the generated Service interface, and run the callers from other languages against the same handler. | ||
| toc_max_heading_level: 4 | ||
| unlisted: true | ||
| tags: | ||
| - Nexus | ||
| - Java SDK | ||
| --- | ||
|
|
||
| Call the approval Operations from a Workflow in the caller Namespace. The caller knows two things — the Endpoint name and the contract from [step 1](/develop/java/nexus/development-walkthrough/define-the-data-contract) — and nothing else about the handler. | ||
|
|
||
| The caller built here is Java, the same language as the handler, but nothing about the handler requires that. [Call it from another language](#call-it-from-another-language) covers the cross-language case, which is the same call against the same Endpoint. | ||
|
|
||
| ## What the caller gets from the contract | ||
|
|
||
| The caller does not hand-write request types, response types, or Operation names. [Step 2](/develop/java/nexus/development-walkthrough/generate-code) generated all of it from the contract, and the caller works against that generated code: | ||
|
|
||
| - **A Service definition** naming the Service and its Operations, so an Operation name is a symbol rather than a string you can misspell. | ||
| - **Typed models** for every input and output in the contract. | ||
| - **Runtime validators** that reject a payload violating the contract before it reaches the wire. | ||
|
|
||
| The practical effect is that the contract is enforced twice. A field the contract does not have fails at build time in a typed language, and a payload the contract forbids fails at the boundary rather than inside the handler's Workflow. | ||
|
|
||
| ## Call the Operations from a caller Workflow | ||
|
|
||
| The flow follows the walkthrough sample problem. Check whether the purchase needs approval at all; if it does, request one and wait for the decision. | ||
|
|
||
| In Java, the generated Service interface works directly as a Nexus Service stub. Create it inside the caller Workflow with the Endpoint name and Operation options, then call its methods as if they were local. | ||
|
|
||
| <!--SNIPSTART samples-java-nexus-walkthrough-caller-workflow--> | ||
| <!--SNIPEND--> | ||
|
|
||
| The Endpoint name is not in the Workflow. It is bound once when the caller Worker registers the | ||
| Workflow, so the Workflow refers to the Service by its contract alone: | ||
|
|
||
| <!--SNIPSTART samples-java-nexus-walkthrough-caller-worker--> | ||
| <!--SNIPEND--> | ||
|
|
||
| Nothing in this caller is aware of how the handler is built. It does not know which Task Queue the handler's Worker polls, or that `requestApproval` is backed by a Workflow while `checkApprovalRequired` is backed by nothing at all. It knows the Endpoint name and the contract. | ||
|
|
||
| That is the property worth pausing on: the handler team can change what backs an Operation, move the handler to another Namespace, or rewrite it in another language, and this caller keeps working. | ||
|
|
||
| ## Await the decision | ||
|
|
||
| `requestApproval` returns `APPROVED` or `DENIED`. That value is the approval Workflow's return value, delivered to the caller through the Nexus completion callback when the Workflow finishes. | ||
|
|
||
| The caller does not poll. It awaits the Operation, and the wait is durable — the caller Workflow can be evicted, the Worker can restart, and the result still arrives. | ||
|
|
||
| `checkApprovalRequired` behaves differently and it is worth noticing the contrast. It returns during the call, because nothing durable backs it. There is no callback, no Operation token, and nothing to await. | ||
|
|
||
| ### Set timeouts | ||
|
|
||
| A caller sets three timeouts on a Nexus Operation, each bounding a different stage: | ||
|
|
||
| - **Schedule-to-close** bounds the whole Operation, from scheduling to completion. Set it to reflect how long an approval can legitimately take — a human approval measured in days needs a timeout in days, and the default is not going to be right. | ||
| - **Schedule-to-start** bounds how long the caller waits for the handler to pick the Operation up. Set it when you want a handler that is down to fail fast, even though the approval itself may run for days. | ||
| - **Start-to-close** bounds an asynchronous Operation after it has started. Synchronous Operations like `checkApprovalRequired` ignore it, because they complete as part of the start request. | ||
|
|
||
| See [Nexus Operations](/nexus/operations#timeouts) for the full timeout model. | ||
|
|
||
| ## Call it from another language | ||
|
|
||
| The caller does not have to be written in the same language as the handler. Each language has a sample repository that builds this same approval Service from this same contract, and each one carries a working caller as well as a working handler: | ||
|
|
||
| | Language | Sample | | ||
| | --- | --- | | ||
| | Go | `{sample repo link}` | | ||
| | Python | `{sample repo link}` | | ||
| | TypeScript | `{sample repo link}` | | ||
|
|
||
| Check the README in each repository for how to run its client. Point it at the Endpoint created in [step 5](/develop/java/nexus/development-walkthrough/publish-in-nexus) and it drives the Java handler built here, with no changes on either side. | ||
|
|
||
| The interop runs both directions. Every one of those clients can call this Java Service, and the Java caller built in this step can call the Service from any of those repositories. The contract is the only thing the two sides share, so neither side needs to know the other's language, Namespace, or deployment. | ||
|
|
||
| To generate a caller for another language from this contract yourself rather than running a sample, see [Generate code](/nexus/client-code-generator#generate-code). | ||
|
|
||
| ## Calling without a caller Workflow | ||
|
|
||
| A caller Workflow is the usual pattern and the one this walkthrough uses, because a Workflow gives the call durability and lets you orchestrate around it. | ||
|
|
||
| If you only need to run one Operation and have nothing to orchestrate, a Client can start an Operation directly with no caller Workflow at all. That is a [Standalone Nexus Operation](/standalone-nexus-operation), and it uses the same Service contract, the same handler, and the same Endpoint — only the caller side differs. See [Java: Standalone Operations](/develop/java/nexus/standalone-operations). | ||
|
|
||
| `checkApprovalRequired` is a natural fit for this. A caller that only wants to know whether approval is needed has nothing to orchestrate and no result to await. | ||
|
|
||
| ## Next | ||
|
|
||
| The Service can start an approval and return a decision. | ||
|
|
||
| **[Step 7 - Add messaging](/develop/java/nexus/development-walkthrough/add-messaging)** - let callers interact with an approval while it is pending. | ||
|
|
||
| Back to the [Microservice Development Walkthrough overview](/develop/java/nexus/development-walkthrough). | ||
|
|
||
| :::tip RESOURCES | ||
|
|
||
| - [Nexus Operations](/nexus/operations) for the Operation lifecycle and timeouts. | ||
| - [Java Nexus feature guide](/develop/java/nexus/feature-guide) for the caller API. | ||
| - [Nexus Client Code Generator](/nexus/client-code-generator) for generating callers in other languages. | ||
|
|
||
| ::: |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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 is good information, but not useful to the guide. The guide should stay a bit tighter to How-to-Guide, move this content to Reference.