From 4de729ad09bc7034939105993e5dd865833f61c7 Mon Sep 17 00:00:00 2001 From: Durable Workflow Date: Fri, 23 Oct 2026 14:51:07 +0000 Subject: [PATCH 1/2] docs: explain Rust stable activity identity in all locales --- docs/constraints/execution-guarantees.md | 4 ++ docs/polyglot/rust.md | 38 +++++++++++++++++++ .../constraints/execution-guarantees.md | 4 ++ .../current/polyglot/rust.md | 38 +++++++++++++++++++ i18n/de/source-hashes.json | 4 +- .../constraints/execution-guarantees.md | 4 ++ .../current/polyglot/rust.md | 38 +++++++++++++++++++ i18n/es/source-hashes.json | 4 +- .../constraints/execution-guarantees.md | 4 ++ .../current/polyglot/rust.md | 38 +++++++++++++++++++ i18n/fr/source-hashes.json | 4 +- .../constraints/execution-guarantees.md | 4 ++ .../current/polyglot/rust.md | 38 +++++++++++++++++++ i18n/ja/source-hashes.json | 4 +- .../constraints/execution-guarantees.md | 4 ++ .../current/polyglot/rust.md | 38 +++++++++++++++++++ i18n/pt-BR/source-hashes.json | 4 +- .../constraints/execution-guarantees.md | 4 ++ .../current/polyglot/rust.md | 38 +++++++++++++++++++ i18n/uk/source-hashes.json | 4 +- .../constraints/execution-guarantees.md | 4 ++ .../current/polyglot/rust.md | 38 +++++++++++++++++++ i18n/zh-Hans/source-hashes.json | 4 +- 23 files changed, 350 insertions(+), 14 deletions(-) diff --git a/docs/constraints/execution-guarantees.md b/docs/constraints/execution-guarantees.md index e1ffc1e9f2e..5275a14e301 100644 --- a/docs/constraints/execution-guarantees.md +++ b/docs/constraints/execution-guarantees.md @@ -138,6 +138,10 @@ final class ChargeCard extends Activity } ``` +### Service-mode activity identity {#service-activity-identity} + +For Rust service-mode activities, SDK **4.9.0 or newer** exposes the original optional `activity_execution_id()`, `workflow_id()` (instance) and `run_id()` through `ActivityContext`. Use the logical activity ID across retries; missing claim fields stay `None`, and a per-attempt task/attempt ID is not a replacement. The [Rust handler recipe](../polyglot/rust.md#activity-identity) derives a downstream key and explains older-Server, local-activity and Server-free-test limits. A key still needs an idempotent downstream API or durable effect ledger; these accessors do not provide resumable checkpoints. + ## What Developers Must Make Idempotent You do **not** need to make workflow replay itself idempotent. The framework diff --git a/docs/polyglot/rust.md b/docs/polyglot/rust.md index 629c7495a48..370ece39f78 100644 --- a/docs/polyglot/rust.md +++ b/docs/polyglot/rust.md @@ -282,6 +282,44 @@ pub fn register_charge(worker: &mut Worker) { Local activities and direct `testing::WorkflowEnvironment::run_activity` calls have no received Server snapshot and report unknown policy. Fresh `run_workflow` tests expose the modeled snapshot recorded in their generated history. These test semantics do not prove a deployed Server sends a policy. See [ActivityRetryInfo](https://rust.durable-workflow.com/durable_workflow/struct.ActivityRetryInfo.html) and [ActivityAttemptLimit](https://rust.durable-workflow.com/durable_workflow/enum.ActivityAttemptLimit.html). +## Stable activity identity and downstream idempotency {#activity-identity} + +Rust SDK **4.9.0 or newer** exposes the original received identity through `ActivityContext`. Check the installed crate in `Cargo.lock`; the separately selected installation pin above can be older. These accessors return immutable `Option<&str>` values captured from the original claim, including worker-session activities. + +| Accessor | Identity and use | +| --- | --- | +| `activity_execution_id()` | One logical activity execution across retries; use it to deduplicate an external operation. | +| `workflow_id()` | The owning workflow **instance** ID; use it for business correlation. | +| `run_id()` | The owning workflow **run** ID; use it to correlate this particular run. | + +Derive a key for a particular operation and pass it to an idempotent downstream API or durable effect ledger. This handler only constructs the key: it does not charge a payment or implement downstream deduplication. It refuses missing activity identity before any effect; an application can instead supply its own explicitly stable business key. + +```rust +use durable_workflow::{json, ActivityError, Worker}; + +pub fn register_charge(worker: &mut Worker) { + worker.register_activity("charge", |ctx, _| async move { + let execution_id = ctx.activity_execution_id().ok_or_else(|| { + ActivityError::new("MissingActivityIdentity", "Server activity identity is required") + .non_retryable(true) + })?; + // Pass this key to an idempotent downstream API or durable effect ledger. + let key = format!("payments:charge:{execution_id}"); + Ok(json!({ + "idempotency_key": key, + "workflow_id": ctx.workflow_id(), + "run_id": ctx.run_id(), + })) + }); +} +``` + +When an older Server omits these fields, they remain `None`. Never replace a missing logical activity ID with a per-attempt task ID, attempt ID or attempt number: that would produce a different key on retry. Inline local activities can receive real parent workflow/run IDs, but have no Server activity execution ID before the Server records their command. Server-free activity tests have no received claim identity. + +A stable key makes duplicate effects preventable only when the downstream system honors that key. Activity delivery remains at-least-once; this API does not make external work exactly-once, restore heartbeat progress or implement resumable activity checkpoints. + +See [ActivityContext identity accessors](https://rust.durable-workflow.com/durable_workflow/struct.ActivityContext.html#method.activity_execution_id) and the [normal installed 4.9.0 receipt](https://github.com/durable-workflow/sdk-rust/issues/139#issuecomment-6367230500) for ordinary/cooperative, local and worker-session controls. See [execution guarantees](../constraints/execution-guarantees.md#service-activity-identity) for the shared idempotency contract. + ## Local activities Rust SDK 3.1.0 adds inline local execution on workers configured with diff --git a/i18n/de/docusaurus-plugin-content-docs/current/constraints/execution-guarantees.md b/i18n/de/docusaurus-plugin-content-docs/current/constraints/execution-guarantees.md index d099561acd6..8d1abd2cc1a 100644 --- a/i18n/de/docusaurus-plugin-content-docs/current/constraints/execution-guarantees.md +++ b/i18n/de/docusaurus-plugin-content-docs/current/constraints/execution-guarantees.md @@ -110,6 +110,10 @@ final class ChargeCard extends Activity } ``` +### Aktivitätsidentität im Service-Modus {#service-activity-identity} + +Für Rust-Aktivitäten im Service-Modus liefert SDK **4.9.0 oder neuer** die ursprünglichen optionalen Werte `activity_execution_id()`, `workflow_id()` (Instanz) und `run_id()` über `ActivityContext`. Nutzen Sie die logische Aktivitäts-ID über Retries hinweg; fehlende Claim-Felder bleiben `None`, und eine Task- oder Versuch-ID ist kein Ersatz. Das [Rust-Handler-Beispiel](../polyglot/rust.md#activity-identity) leitet einen externen Schlüssel ab und erläutert Grenzen älterer Server, lokaler Aktivitäten und serverfreier Tests. Der Schlüssel benötigt weiterhin eine idempotente externe API oder ein dauerhaftes Effektregister; diese Methoden liefern keine fortsetzbaren Checkpoints. + ## Was die Anwendung idempotent machen muss {#what-developers-must-make-idempotent} Workflow-Replay selbst müssen Sie nicht idempotent machen. Das Framework rekonstruiert den Zustand aus der festgeschriebenen Historie. diff --git a/i18n/de/docusaurus-plugin-content-docs/current/polyglot/rust.md b/i18n/de/docusaurus-plugin-content-docs/current/polyglot/rust.md index 20f2f65261c..a19b9fb7496 100644 --- a/i18n/de/docusaurus-plugin-content-docs/current/polyglot/rust.md +++ b/i18n/de/docusaurus-plugin-content-docs/current/polyglot/rust.md @@ -282,6 +282,44 @@ pub fn register_charge(worker: &mut Worker) { Lokale Aktivitäten und direkte Aufrufe von `testing::WorkflowEnvironment::run_activity` haben keinen empfangenen Server-Snapshot und melden eine unbekannte Richtlinie. Neue `run_workflow`-Tests zeigen den modellierten Snapshot aus ihrer erzeugten Historie. Diese Testsemantik belegt nicht, dass ein bereitgestellter Server eine Richtlinie sendet. Siehe [ActivityRetryInfo](https://rust.durable-workflow.com/durable_workflow/struct.ActivityRetryInfo.html) und [ActivityAttemptLimit](https://rust.durable-workflow.com/durable_workflow/enum.ActivityAttemptLimit.html). +## Stabile Aktivitätsidentität und Idempotenz externer Effekte {#activity-identity} + +Rust SDK **4.9.0 oder neuer** stellt die ursprünglich empfangene Identität über `ActivityContext` bereit. Prüfen Sie den installierten Crate in `Cargo.lock`: Die oben unabhängig gewählte Installationsversion kann älter sein. Die Methoden liefern unveränderliche `Option<&str>`-Werte aus dem ursprünglichen Claim, auch bei Aktivitäten in Worker-Sessions. + +| Methode | Identität und Verwendung | +| --- | --- | +| `activity_execution_id()` | Eine logische Aktivitätsausführung über Wiederholungsversuche hinweg; zur Deduplizierung einer externen Operation. | +| `workflow_id()` | ID der zugehörigen Workflow-**Instanz**; zur fachlichen Zuordnung. | +| `run_id()` | ID des zugehörigen Workflow-**Runs**; zur Zuordnung dieses konkreten Laufs. | + +Leiten Sie einen Schlüssel für eine bestimmte Operation ab und übergeben Sie ihn an eine idempotente externe API oder ein dauerhaftes Effektregister. Dieser Handler erzeugt nur den Schlüssel: Er belastet keine Zahlung und implementiert keine externe Deduplizierung. Fehlt die Aktivitätsidentität, lehnt er vor jedem Effekt ab; alternativ kann die Anwendung einen eigenen ausdrücklich stabilen fachlichen Schlüssel liefern. + +```rust +use durable_workflow::{json, ActivityError, Worker}; + +pub fn register_charge(worker: &mut Worker) { + worker.register_activity("charge", |ctx, _| async move { + let execution_id = ctx.activity_execution_id().ok_or_else(|| { + ActivityError::new("MissingActivityIdentity", "Server activity identity is required") + .non_retryable(true) + })?; + // Pass this key to an idempotent downstream API or durable effect ledger. + let key = format!("payments:charge:{execution_id}"); + Ok(json!({ + "idempotency_key": key, + "workflow_id": ctx.workflow_id(), + "run_id": ctx.run_id(), + })) + }); +} +``` + +Lässt ein älterer Server diese Felder aus, bleiben sie `None`. Ersetzen Sie eine fehlende logische Aktivitäts-ID niemals durch eine Task-ID, Versuch-ID oder Versuchsnummer: Der Schlüssel würde sich beim Retry ändern. Inline Local Activities können die tatsächlichen Workflow-/Run-IDs des Eltern-Tasks erhalten, haben aber keine serverseitige Aktivitätsausführungs-ID, bevor der Server ihren Befehl speichert. Serverfreie Aktivitätstests besitzen keine empfangene Claim-Identität. + +Ein stabiler Schlüssel ermöglicht die Vermeidung doppelter Effekte nur, wenn das externe System ihn beachtet. Die Zustellung bleibt mindestens einmal; diese API macht externe Effekte nicht genau einmal, stellt keinen Heartbeat-Fortschritt wieder her und implementiert keine fortsetzbaren Aktivitäts-Checkpoints. + +Siehe die [Identitätsmethoden von ActivityContext](https://rust.durable-workflow.com/durable_workflow/struct.ActivityContext.html#method.activity_execution_id) und die [Prüfung der normalen Installation4.9.0](https://github.com/durable-workflow/sdk-rust/issues/139#issuecomment-6367230500) mit Ordinary-/Cooperative-, Local- und Worker-Session-Kontrollen. Der gemeinsame Vertrag steht unter [Ausführungsgarantien](../constraints/execution-guarantees.md#service-activity-identity). + ## Lokale Aktivitäten {#local-activities} Rust SDK 3.1.0 ergänzt lokale Inline-Ausführung auf Workern mit diff --git a/i18n/de/source-hashes.json b/i18n/de/source-hashes.json index f96f8dd692a..f3d1cd198fb 100644 --- a/i18n/de/source-hashes.json +++ b/i18n/de/source-hashes.json @@ -14,7 +14,7 @@ "configuration/publishing-config.md": "c757acd749c0d2696a6e19484249c9298dd15970ce0cf2ae0e6d2dfd82c8b6d6", "constraints/activity-constraints.md": "5a953d0e95e750b6c02d1c72b72199fb3ff4687540cebc56aa3b216cf667bb05", "constraints/constraints-summary.md": "fb48d01502388fc3821eae3790f470ed29cec91545420450f96fc77b84e589f1", - "constraints/execution-guarantees.md": "e0903f1d6d7461191f2190453f9f96ce9bdcf6811e7e99c7d51f81e2f58ef27d", + "constraints/execution-guarantees.md": "c24aaff70bfcf50366459ec698ced67adff1e02c1b0ca23c8178a13873037f5a", "constraints/idempotent-vs-deterministic.md": "f7396f01a4111ce187e751b009c1efb96f5538e8a602006eed24f7b1d8f44adf", "constraints/overview.md": "fd6c842c6c22d6f0df37a52de15ca74b34664f5ecd78af0c08b1e0cdb9a2be1f", "constraints/structural-limits.md": "3dfeac3620285f5271653c31392e26e5111fe814ece08fc44367b5786d99c47d", @@ -84,7 +84,7 @@ "polyglot/prerelease-history-migration.md": "a57f05f492228a8a67791f9152648a1e5f80856325b78777cf63b6ef49b7413c", "polyglot/python.md": "d55056ca7638df07b7267bc6d62e635b954957b99620478e861df90558860df3", "polyglot/rust-cloud-quickstart.md": "2303434fc9302a81a8381ad4836423ef9952eb3201a4574c432254e3cb68c5f3", - "polyglot/rust.md": "f6ac50f08ee1a7e94686403df5880e771cd306aa07aed69c73261e5a25f6d78f", + "polyglot/rust.md": "5ff66bcb7e5369bcffd8611342a35c27028cac5a4ee376e86d90334a2b12d365", "polyglot/server-api-reference.md": "e94af77a13b341d6fdc9941d4ee94e5053ab932d2e77069b238eb33351414e83", "polyglot/server-config-reference.md": "edb4cf00b9df2c9946b32a81c6bb2c4db6eaee89794b85286c61c235a4846414", "polyglot/server-role-topology.md": "3d048f0c6b5f179399622508f51e67fff8aa5a6d5b2492533fc720eeec2c27f2", diff --git a/i18n/es/docusaurus-plugin-content-docs/current/constraints/execution-guarantees.md b/i18n/es/docusaurus-plugin-content-docs/current/constraints/execution-guarantees.md index 64e53cff35a..3c9813b8757 100644 --- a/i18n/es/docusaurus-plugin-content-docs/current/constraints/execution-guarantees.md +++ b/i18n/es/docusaurus-plugin-content-docs/current/constraints/execution-guarantees.md @@ -139,6 +139,10 @@ final class ChargeCard extends Activity } ``` +### Identidad de actividad en modo servicio {#service-activity-identity} + +Para actividades Rust en modo servicio, SDK **4.9.0 o posterior** expone los valores originales opcionales `activity_execution_id()`, `workflow_id()` (instancia) y `run_id()` mediante `ActivityContext`. Usa el ID lógico de actividad entre reintentos; los campos ausentes del claim siguen en `None`, y un ID de tarea o intento no los sustituye. La [receta del handler Rust](../polyglot/rust.md#activity-identity) deriva una clave externa y explica los límites de Server anteriores, actividades locales y pruebas sin Server. La clave sigue necesitando una API externa idempotente o un registro duradero de efectos; estos métodos no proporcionan checkpoints reanudables. + ## Qué debe ser idempotente en tu aplicación {#what-developers-must-make-idempotent} No necesitas hacer idempotente la reproducción del workflow. El framework se diff --git a/i18n/es/docusaurus-plugin-content-docs/current/polyglot/rust.md b/i18n/es/docusaurus-plugin-content-docs/current/polyglot/rust.md index 5639cbab330..ff0fcd10848 100644 --- a/i18n/es/docusaurus-plugin-content-docs/current/polyglot/rust.md +++ b/i18n/es/docusaurus-plugin-content-docs/current/polyglot/rust.md @@ -229,6 +229,44 @@ pub fn register_charge(worker: &mut Worker) { Las actividades locales y las llamadas directas a `testing::WorkflowEnvironment::run_activity` no tienen una instantánea recibida del Server y devuelven política desconocida. Las pruebas nuevas con `run_workflow` exponen la instantánea modelada que registran en su historial generado. Esta semántica de pruebas no demuestra que un Server desplegado envíe una política. Consulta [ActivityRetryInfo](https://rust.durable-workflow.com/durable_workflow/struct.ActivityRetryInfo.html) y [ActivityAttemptLimit](https://rust.durable-workflow.com/durable_workflow/enum.ActivityAttemptLimit.html). +## Identidad estable de actividad e idempotencia externa {#activity-identity} + +Rust SDK **4.9.0 o posterior** expone la identidad recibida originalmente mediante `ActivityContext`. Comprueba el crate instalado en `Cargo.lock`: la versión de instalación seleccionada arriba por separado puede ser anterior. Estos métodos devuelven valores inmutables `Option<&str>` capturados del claim original, también para actividades de sesiones de worker. + +| Método | Identidad y uso | +| --- | --- | +| `activity_execution_id()` | Una ejecución lógica de actividad a través de sus reintentos; úsala para deduplicar una operación externa. | +| `workflow_id()` | ID de la **instancia** del workflow propietario; úsalo para correlación de negocio. | +| `run_id()` | ID del **run** del workflow propietario; úsalo para correlacionar esa ejecución concreta. | + +Deriva una clave para una operación concreta y pásala a una API externa idempotente o a un registro duradero de efectos. Este handler solo construye la clave: no cobra un pago ni implementa la deduplicación externa. Rechaza la ausencia de identidad antes de cualquier efecto; la aplicación puede proporcionar en su lugar una clave de negocio explícitamente estable. + +```rust +use durable_workflow::{json, ActivityError, Worker}; + +pub fn register_charge(worker: &mut Worker) { + worker.register_activity("charge", |ctx, _| async move { + let execution_id = ctx.activity_execution_id().ok_or_else(|| { + ActivityError::new("MissingActivityIdentity", "Server activity identity is required") + .non_retryable(true) + })?; + // Pass this key to an idempotent downstream API or durable effect ledger. + let key = format!("payments:charge:{execution_id}"); + Ok(json!({ + "idempotency_key": key, + "workflow_id": ctx.workflow_id(), + "run_id": ctx.run_id(), + })) + }); +} +``` + +Si un Server anterior omite estos campos, permanecen en `None`. Nunca sustituyas el ID lógico ausente por un ID de tarea, ID de intento o número de intento: la clave cambiaría en cada reintento. Las actividades locales inline pueden recibir los ID reales del workflow/run padre, pero no tienen ID de ejecución de actividad del Server antes de que este registre su comando. Las pruebas de actividad sin Server no tienen identidad de claim recibida. + +Una clave estable solo permite evitar efectos duplicados si el sistema externo respeta esa clave. La entrega sigue siendo al menos una vez; esta API no convierte los efectos externos en exactamente una vez, no restaura el progreso del heartbeat ni implementa checkpoints reanudables de actividad. + +Consulta los [métodos de identidad de ActivityContext](https://rust.durable-workflow.com/durable_workflow/struct.ActivityContext.html#method.activity_execution_id) y la [verificación de instalación normal 4.9.0](https://github.com/durable-workflow/sdk-rust/issues/139#issuecomment-6367230500) con controles ordinary/cooperative, locales y de sesiones de worker. El contrato común está en [garantías de ejecución](../constraints/execution-guarantees.md#service-activity-identity). + ## Actividades locales {#local-activities} El SDK de Rust 3.1.0 añade ejecución local en el propio worker con `Worker::local_activities(true)`. Registra callbacks con los métodos ordinarios de registro de actividades y utiliza los métodos de actividad local del contexto de workflow. Consulta el [ejemplo ejecutable](https://github.com/durable-workflow/sdk-rust/blob/3.1.0/examples/local_activities.rs) y la [referencia de LocalActivityOptions](https://rust.durable-workflow.com/durable_workflow/struct.LocalActivityOptions.html) para configurar reintentos y tiempos de espera. diff --git a/i18n/es/source-hashes.json b/i18n/es/source-hashes.json index f96f8dd692a..f3d1cd198fb 100644 --- a/i18n/es/source-hashes.json +++ b/i18n/es/source-hashes.json @@ -14,7 +14,7 @@ "configuration/publishing-config.md": "c757acd749c0d2696a6e19484249c9298dd15970ce0cf2ae0e6d2dfd82c8b6d6", "constraints/activity-constraints.md": "5a953d0e95e750b6c02d1c72b72199fb3ff4687540cebc56aa3b216cf667bb05", "constraints/constraints-summary.md": "fb48d01502388fc3821eae3790f470ed29cec91545420450f96fc77b84e589f1", - "constraints/execution-guarantees.md": "e0903f1d6d7461191f2190453f9f96ce9bdcf6811e7e99c7d51f81e2f58ef27d", + "constraints/execution-guarantees.md": "c24aaff70bfcf50366459ec698ced67adff1e02c1b0ca23c8178a13873037f5a", "constraints/idempotent-vs-deterministic.md": "f7396f01a4111ce187e751b009c1efb96f5538e8a602006eed24f7b1d8f44adf", "constraints/overview.md": "fd6c842c6c22d6f0df37a52de15ca74b34664f5ecd78af0c08b1e0cdb9a2be1f", "constraints/structural-limits.md": "3dfeac3620285f5271653c31392e26e5111fe814ece08fc44367b5786d99c47d", @@ -84,7 +84,7 @@ "polyglot/prerelease-history-migration.md": "a57f05f492228a8a67791f9152648a1e5f80856325b78777cf63b6ef49b7413c", "polyglot/python.md": "d55056ca7638df07b7267bc6d62e635b954957b99620478e861df90558860df3", "polyglot/rust-cloud-quickstart.md": "2303434fc9302a81a8381ad4836423ef9952eb3201a4574c432254e3cb68c5f3", - "polyglot/rust.md": "f6ac50f08ee1a7e94686403df5880e771cd306aa07aed69c73261e5a25f6d78f", + "polyglot/rust.md": "5ff66bcb7e5369bcffd8611342a35c27028cac5a4ee376e86d90334a2b12d365", "polyglot/server-api-reference.md": "e94af77a13b341d6fdc9941d4ee94e5053ab932d2e77069b238eb33351414e83", "polyglot/server-config-reference.md": "edb4cf00b9df2c9946b32a81c6bb2c4db6eaee89794b85286c61c235a4846414", "polyglot/server-role-topology.md": "3d048f0c6b5f179399622508f51e67fff8aa5a6d5b2492533fc720eeec2c27f2", diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/constraints/execution-guarantees.md b/i18n/fr/docusaurus-plugin-content-docs/current/constraints/execution-guarantees.md index 058905d0308..422ada0c330 100644 --- a/i18n/fr/docusaurus-plugin-content-docs/current/constraints/execution-guarantees.md +++ b/i18n/fr/docusaurus-plugin-content-docs/current/constraints/execution-guarantees.md @@ -110,6 +110,10 @@ final class ChargeCard extends Activity } ``` +### Identité des activités en mode service {#service-activity-identity} + +Pour les activités Rust en mode service, le SDK **4.9.0 ou ultérieur** expose les valeurs initiales facultatives `activity_execution_id()`, `workflow_id()` (instance) et `run_id()` via `ActivityContext`. Utilisez l’ID logique d’activité entre les retries ; les champs absents du claim restent `None`, et un ID de tâche ou de tentative ne les remplace pas. La [recette du handler Rust](../polyglot/rust.md#activity-identity) dérive une clé externe et précise les limites des anciens Server, des activités locales et des tests sans Server. La clé exige toujours une API externe idempotente ou un registre durable des effets ; ces méthodes ne fournissent pas de checkpoints permettant une reprise. + ## Effets que l’application doit rendre idempotents {#what-developers-must-make-idempotent} Vous n’avez pas besoin de rendre la relecture du workflow elle-même idempotente. Le framework gère la relecture en reconstruisant l’état depuis l’historique validé. diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/polyglot/rust.md b/i18n/fr/docusaurus-plugin-content-docs/current/polyglot/rust.md index 1eb2fa09c8d..dcaf5dbba72 100644 --- a/i18n/fr/docusaurus-plugin-content-docs/current/polyglot/rust.md +++ b/i18n/fr/docusaurus-plugin-content-docs/current/polyglot/rust.md @@ -286,6 +286,44 @@ pub fn register_charge(worker: &mut Worker) { Les activités locales et les appels directs à `testing::WorkflowEnvironment::run_activity` n’ont pas d’instantané reçu du Server et indiquent une politique inconnue. Les nouveaux tests `run_workflow` exposent l’instantané modélisé enregistré dans leur historique généré. Cette sémantique de test ne prouve pas qu’un Server déployé transmet une politique. Voir [ActivityRetryInfo](https://rust.durable-workflow.com/durable_workflow/struct.ActivityRetryInfo.html) et [ActivityAttemptLimit](https://rust.durable-workflow.com/durable_workflow/enum.ActivityAttemptLimit.html). +## Identité stable des activités et idempotence des effets externes {#activity-identity} + +Le SDK Rust **4.9.0 ou ultérieur** expose l’identité reçue à l’origine via `ActivityContext`. Vérifiez le crate installé dans `Cargo.lock` : la version d’installation choisie séparément ci-dessus peut être plus ancienne. Ces méthodes renvoient des valeurs `Option<&str>` immuables capturées dans le claim initial, y compris pour les activités des sessions de worker. + +| Méthode | Identité et usage | +| --- | --- | +| `activity_execution_id()` | Une exécution logique d’activité à travers ses tentatives ; servez-vous-en pour dédupliquer une opération externe. | +| `workflow_id()` | ID de l’**instance** de workflow propriétaire ; utilisez-le pour la corrélation métier. | +| `run_id()` | ID du **run** de workflow propriétaire ; utilisez-le pour corréler cette exécution précise. | + +Dérivez une clé pour une opération précise et transmettez-la à une API externe idempotente ou à un registre durable des effets. Ce handler construit seulement la clé : il ne débite aucun paiement et ne réalise pas la déduplication externe. Il refuse une identité absente avant tout effet ; l’application peut aussi fournir sa propre clé métier explicitement stable. + +```rust +use durable_workflow::{json, ActivityError, Worker}; + +pub fn register_charge(worker: &mut Worker) { + worker.register_activity("charge", |ctx, _| async move { + let execution_id = ctx.activity_execution_id().ok_or_else(|| { + ActivityError::new("MissingActivityIdentity", "Server activity identity is required") + .non_retryable(true) + })?; + // Pass this key to an idempotent downstream API or durable effect ledger. + let key = format!("payments:charge:{execution_id}"); + Ok(json!({ + "idempotency_key": key, + "workflow_id": ctx.workflow_id(), + "run_id": ctx.run_id(), + })) + }); +} +``` + +Lorsqu’un ancien Server omet ces champs, ils restent `None`. Ne remplacez jamais un ID logique absent par un ID de tâche, un ID de tentative ou un numéro de tentative : la clé changerait lors du retry. Les activités locales inline peuvent recevoir les vrais ID du workflow/run parent, mais ne possèdent pas d’ID d’exécution d’activité du Server avant l’enregistrement de leur commande. Les tests d’activité sans Server ne reçoivent aucune identité de claim. + +Une clé stable ne permet d’éviter les effets en double que si le système externe respecte cette clé. La livraison reste au moins une fois ; cette API ne rend pas les effets externes exactement une fois, ne restaure pas la progression des heartbeats et ne fournit pas de checkpoints d’activité permettant une reprise. + +Consultez les [méthodes d’identité d’ActivityContext](https://rust.durable-workflow.com/durable_workflow/struct.ActivityContext.html#method.activity_execution_id) et la [vérification d’installation normale 4.9.0](https://github.com/durable-workflow/sdk-rust/issues/139#issuecomment-6367230500) avec les contrôles ordinary/cooperative, locaux et de sessions de worker. Le contrat commun figure dans les [garanties d’exécution](../constraints/execution-guarantees.md#service-activity-identity). + ## Activités locales {#local-activities} Le SDK Rust 3.1.0 ajoute l’exécution locale en ligne sur les workers configurés diff --git a/i18n/fr/source-hashes.json b/i18n/fr/source-hashes.json index f96f8dd692a..f3d1cd198fb 100644 --- a/i18n/fr/source-hashes.json +++ b/i18n/fr/source-hashes.json @@ -14,7 +14,7 @@ "configuration/publishing-config.md": "c757acd749c0d2696a6e19484249c9298dd15970ce0cf2ae0e6d2dfd82c8b6d6", "constraints/activity-constraints.md": "5a953d0e95e750b6c02d1c72b72199fb3ff4687540cebc56aa3b216cf667bb05", "constraints/constraints-summary.md": "fb48d01502388fc3821eae3790f470ed29cec91545420450f96fc77b84e589f1", - "constraints/execution-guarantees.md": "e0903f1d6d7461191f2190453f9f96ce9bdcf6811e7e99c7d51f81e2f58ef27d", + "constraints/execution-guarantees.md": "c24aaff70bfcf50366459ec698ced67adff1e02c1b0ca23c8178a13873037f5a", "constraints/idempotent-vs-deterministic.md": "f7396f01a4111ce187e751b009c1efb96f5538e8a602006eed24f7b1d8f44adf", "constraints/overview.md": "fd6c842c6c22d6f0df37a52de15ca74b34664f5ecd78af0c08b1e0cdb9a2be1f", "constraints/structural-limits.md": "3dfeac3620285f5271653c31392e26e5111fe814ece08fc44367b5786d99c47d", @@ -84,7 +84,7 @@ "polyglot/prerelease-history-migration.md": "a57f05f492228a8a67791f9152648a1e5f80856325b78777cf63b6ef49b7413c", "polyglot/python.md": "d55056ca7638df07b7267bc6d62e635b954957b99620478e861df90558860df3", "polyglot/rust-cloud-quickstart.md": "2303434fc9302a81a8381ad4836423ef9952eb3201a4574c432254e3cb68c5f3", - "polyglot/rust.md": "f6ac50f08ee1a7e94686403df5880e771cd306aa07aed69c73261e5a25f6d78f", + "polyglot/rust.md": "5ff66bcb7e5369bcffd8611342a35c27028cac5a4ee376e86d90334a2b12d365", "polyglot/server-api-reference.md": "e94af77a13b341d6fdc9941d4ee94e5053ab932d2e77069b238eb33351414e83", "polyglot/server-config-reference.md": "edb4cf00b9df2c9946b32a81c6bb2c4db6eaee89794b85286c61c235a4846414", "polyglot/server-role-topology.md": "3d048f0c6b5f179399622508f51e67fff8aa5a6d5b2492533fc720eeec2c27f2", diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/constraints/execution-guarantees.md b/i18n/ja/docusaurus-plugin-content-docs/current/constraints/execution-guarantees.md index 96db01369cd..bac4c362f29 100644 --- a/i18n/ja/docusaurus-plugin-content-docs/current/constraints/execution-guarantees.md +++ b/i18n/ja/docusaurus-plugin-content-docs/current/constraints/execution-guarantees.md @@ -110,6 +110,10 @@ final class ChargeCard extends Activity } ``` +### サービスモードのアクティビティ識別子 {#service-activity-identity} + +Rust のサービスモードでは、SDK **4.9.0 以降**の `ActivityContext` から、元の任意フィールド `activity_execution_id()`、`workflow_id()`(インスタンス)、`run_id()` を取得できます。再試行をまたぐ論理アクティビティ ID を使ってください。claim の欠落フィールドは `None` のままで、試行ごとの task/attempt ID は代用になりません。[Rust ハンドラーの例](../polyglot/rust.md#activity-identity)では外部キーを作り、旧 Server、local activity、Server を使わないテストの制限を説明しています。キーには依然として冪等な外部 API または永続的な副作用台帳が必要です。これらのメソッドは再開可能な checkpoint を提供しません。 + ## 開発者が冪等にする処理 {#what-developers-must-make-idempotent} ワークフローのリプレイ自体を冪等にする必要はありません。フレームワークが確定済み履歴から状態を再構築して処理します。 diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/polyglot/rust.md b/i18n/ja/docusaurus-plugin-content-docs/current/polyglot/rust.md index 3be2b0e8a28..9391e73f2a8 100644 --- a/i18n/ja/docusaurus-plugin-content-docs/current/polyglot/rust.md +++ b/i18n/ja/docusaurus-plugin-content-docs/current/polyglot/rust.md @@ -229,6 +229,44 @@ pub fn register_charge(worker: &mut Worker) { ローカルアクティビティと `testing::WorkflowEnvironment::run_activity` の直接呼び出しには、受信した Server スナップショットがなく、ポリシーは不明になります。新規の `run_workflow` テストでは、生成した履歴に記録するモデル上のスナップショットを公開します。このテスト仕様は、デプロイ済み Server がポリシーを送信する証明にはなりません。[ActivityRetryInfo](https://rust.durable-workflow.com/durable_workflow/struct.ActivityRetryInfo.html) と [ActivityAttemptLimit](https://rust.durable-workflow.com/durable_workflow/enum.ActivityAttemptLimit.html) を参照してください。 +## 安定したアクティビティ識別子と外部処理の冪等性 {#activity-identity} + +Rust SDK **4.9.0 以降**では、`ActivityContext` から最初に受信した識別子を取得できます。`Cargo.lock` でインストール済み crate を確認してください。上で独立に選択されているインストール指定は旧版の場合があります。これらのメソッドは、worker session のアクティビティも含め、元の claim から保持した不変の `Option<&str>` 値を返します。 + +| メソッド | 識別対象と用途 | +| --- | --- | +| `activity_execution_id()` | 再試行を通じて同じ論理アクティビティ実行を識別します。外部操作の重複排除に使います。 | +| `workflow_id()` | 所有元ワークフローの**インスタンス** ID。業務上の関連付けに使います。 | +| `run_id()` | 所有元ワークフローの **run** ID。その実行を関連付けるために使います。 | + +特定の操作用のキーを作り、冪等な外部 API または永続的な副作用台帳へ渡してください。このハンドラーはキーを作るだけで、決済や外部の重複排除は実装しません。アクティビティ識別子がなければ、副作用の前に拒否します。代わりに、アプリケーションが明示的に安定した業務キーを渡すこともできます。 + +```rust +use durable_workflow::{json, ActivityError, Worker}; + +pub fn register_charge(worker: &mut Worker) { + worker.register_activity("charge", |ctx, _| async move { + let execution_id = ctx.activity_execution_id().ok_or_else(|| { + ActivityError::new("MissingActivityIdentity", "Server activity identity is required") + .non_retryable(true) + })?; + // Pass this key to an idempotent downstream API or durable effect ledger. + let key = format!("payments:charge:{execution_id}"); + Ok(json!({ + "idempotency_key": key, + "workflow_id": ctx.workflow_id(), + "run_id": ctx.run_id(), + })) + }); +} +``` + +旧 Server がこれらのフィールドを省略した場合、値は `None` のままです。欠けた論理アクティビティ ID を試行ごとの task ID、attempt ID、試行番号で代用しないでください。再試行時にキーが変わってしまいます。インラインの local activity には実際の親 workflow/run ID が渡ることがありますが、Server がコマンドを記録する前には Server の activity execution ID がありません。Server を使わないアクティビティテストにも受信した claim 識別子はありません。 + +安定したキーで副作用の重複を防げるのは、外部システムがそのキーを尊重する場合だけです。アクティビティ配送は引き続き少なくとも1回です。この API は外部処理の exactly-once、heartbeat 進捗の復元、再開可能なアクティビティ checkpoint を提供しません。 + +[ActivityContext の識別子メソッド](https://rust.durable-workflow.com/durable_workflow/struct.ActivityContext.html#method.activity_execution_id)と、ordinary/cooperative、local、worker-session の検証を含む[通常インストール 4.9.0 の記録](https://github.com/durable-workflow/sdk-rust/issues/139#issuecomment-6367230500)を参照してください。共通の契約は[実行保証](../constraints/execution-guarantees.md#service-activity-identity)にあります。 + ## ローカルアクティビティ {#local-activities} Rust SDK 3.1.0 は `Worker::local_activities(true)` で設定した Worker にインラインのローカル実行を追加します。通常のアクティビティ登録メソッドでコールバックを登録し、ワークフローコンテキストのローカルアクティビティメソッドを使います。再試行とタイムアウトの設定は[実行可能な例](https://github.com/durable-workflow/sdk-rust/blob/3.1.0/examples/local_activities.rs)と [LocalActivityOptions リファレンス](https://rust.durable-workflow.com/durable_workflow/struct.LocalActivityOptions.html)を参照してください。 diff --git a/i18n/ja/source-hashes.json b/i18n/ja/source-hashes.json index f96f8dd692a..f3d1cd198fb 100644 --- a/i18n/ja/source-hashes.json +++ b/i18n/ja/source-hashes.json @@ -14,7 +14,7 @@ "configuration/publishing-config.md": "c757acd749c0d2696a6e19484249c9298dd15970ce0cf2ae0e6d2dfd82c8b6d6", "constraints/activity-constraints.md": "5a953d0e95e750b6c02d1c72b72199fb3ff4687540cebc56aa3b216cf667bb05", "constraints/constraints-summary.md": "fb48d01502388fc3821eae3790f470ed29cec91545420450f96fc77b84e589f1", - "constraints/execution-guarantees.md": "e0903f1d6d7461191f2190453f9f96ce9bdcf6811e7e99c7d51f81e2f58ef27d", + "constraints/execution-guarantees.md": "c24aaff70bfcf50366459ec698ced67adff1e02c1b0ca23c8178a13873037f5a", "constraints/idempotent-vs-deterministic.md": "f7396f01a4111ce187e751b009c1efb96f5538e8a602006eed24f7b1d8f44adf", "constraints/overview.md": "fd6c842c6c22d6f0df37a52de15ca74b34664f5ecd78af0c08b1e0cdb9a2be1f", "constraints/structural-limits.md": "3dfeac3620285f5271653c31392e26e5111fe814ece08fc44367b5786d99c47d", @@ -84,7 +84,7 @@ "polyglot/prerelease-history-migration.md": "a57f05f492228a8a67791f9152648a1e5f80856325b78777cf63b6ef49b7413c", "polyglot/python.md": "d55056ca7638df07b7267bc6d62e635b954957b99620478e861df90558860df3", "polyglot/rust-cloud-quickstart.md": "2303434fc9302a81a8381ad4836423ef9952eb3201a4574c432254e3cb68c5f3", - "polyglot/rust.md": "f6ac50f08ee1a7e94686403df5880e771cd306aa07aed69c73261e5a25f6d78f", + "polyglot/rust.md": "5ff66bcb7e5369bcffd8611342a35c27028cac5a4ee376e86d90334a2b12d365", "polyglot/server-api-reference.md": "e94af77a13b341d6fdc9941d4ee94e5053ab932d2e77069b238eb33351414e83", "polyglot/server-config-reference.md": "edb4cf00b9df2c9946b32a81c6bb2c4db6eaee89794b85286c61c235a4846414", "polyglot/server-role-topology.md": "3d048f0c6b5f179399622508f51e67fff8aa5a6d5b2492533fc720eeec2c27f2", diff --git a/i18n/pt-BR/docusaurus-plugin-content-docs/current/constraints/execution-guarantees.md b/i18n/pt-BR/docusaurus-plugin-content-docs/current/constraints/execution-guarantees.md index 807375d6c44..89ced36482b 100644 --- a/i18n/pt-BR/docusaurus-plugin-content-docs/current/constraints/execution-guarantees.md +++ b/i18n/pt-BR/docusaurus-plugin-content-docs/current/constraints/execution-guarantees.md @@ -110,6 +110,10 @@ final class ChargeCard extends Activity } ``` +### Identidade de atividade no modo serviço {#service-activity-identity} + +Para atividades Rust no modo serviço, SDK **4.9.0 ou posterior** expõe os valores originais opcionais `activity_execution_id()`, `workflow_id()` (instância) e `run_id()` por `ActivityContext`. Use o ID lógico da atividade entre retries; campos ausentes do claim continuam `None`, e um ID de tarefa ou tentativa não os substitui. A [receita do handler Rust](../polyglot/rust.md#activity-identity) deriva uma chave externa e explica os limites de Servers antigos, atividades locais e testes sem Server. A chave ainda exige uma API externa idempotente ou registro durável de efeitos; esses métodos não oferecem checkpoints retomáveis. + ## O que a aplicação precisa tornar idempotente {#what-developers-must-make-idempotent} Você **não** precisa tornar o próprio replay idempotente. O framework reconstrói o estado a partir do histórico confirmado. diff --git a/i18n/pt-BR/docusaurus-plugin-content-docs/current/polyglot/rust.md b/i18n/pt-BR/docusaurus-plugin-content-docs/current/polyglot/rust.md index aebb702e548..033e66ee347 100644 --- a/i18n/pt-BR/docusaurus-plugin-content-docs/current/polyglot/rust.md +++ b/i18n/pt-BR/docusaurus-plugin-content-docs/current/polyglot/rust.md @@ -281,6 +281,44 @@ pub fn register_charge(worker: &mut Worker) { Atividades locais e chamadas diretas a `testing::WorkflowEnvironment::run_activity` não têm snapshot recebido do Server e informam política desconhecida. Testes novos de `run_workflow` expõem o snapshot modelado registrado no histórico gerado. Essa semântica de testes não comprova que um Server implantado envie uma política. Veja [ActivityRetryInfo](https://rust.durable-workflow.com/durable_workflow/struct.ActivityRetryInfo.html) e [ActivityAttemptLimit](https://rust.durable-workflow.com/durable_workflow/enum.ActivityAttemptLimit.html). +## Identidade estável da atividade e idempotência externa {#activity-identity} + +Rust SDK **4.9.0 ou posterior** expõe a identidade recebida originalmente por `ActivityContext`. Confira o crate instalado em `Cargo.lock`: a versão de instalação selecionada acima de forma independente pode ser mais antiga. Os métodos retornam valores imutáveis `Option<&str>` capturados do claim original, inclusive para atividades de sessões de worker. + +| Método | Identidade e uso | +| --- | --- | +| `activity_execution_id()` | Uma execução lógica de atividade ao longo das tentativas; use para deduplicar uma operação externa. | +| `workflow_id()` | ID da **instância** do workflow proprietário; use para correlação de negócio. | +| `run_id()` | ID do **run** do workflow proprietário; use para correlacionar essa execução específica. | + +Derive uma chave para uma operação específica e passe-a a uma API externa idempotente ou a um registro durável de efeitos. Este handler apenas cria a chave: não cobra um pagamento nem implementa deduplicação externa. Ele recusa a identidade ausente antes de qualquer efeito; a aplicação pode fornecer sua própria chave de negócio explicitamente estável. + +```rust +use durable_workflow::{json, ActivityError, Worker}; + +pub fn register_charge(worker: &mut Worker) { + worker.register_activity("charge", |ctx, _| async move { + let execution_id = ctx.activity_execution_id().ok_or_else(|| { + ActivityError::new("MissingActivityIdentity", "Server activity identity is required") + .non_retryable(true) + })?; + // Pass this key to an idempotent downstream API or durable effect ledger. + let key = format!("payments:charge:{execution_id}"); + Ok(json!({ + "idempotency_key": key, + "workflow_id": ctx.workflow_id(), + "run_id": ctx.run_id(), + })) + }); +} +``` + +Quando um Server antigo omite esses campos, eles permanecem `None`. Nunca substitua o ID lógico ausente por ID de tarefa, ID de tentativa ou número da tentativa: a chave mudaria no retry. Atividades locais inline podem receber os IDs reais do workflow/run pai, mas não têm um ID de execução de atividade do Server antes de ele registrar o comando. Testes de atividade sem Server não têm identidade de claim recebida. + +Uma chave estável só permite impedir efeitos duplicados quando o sistema externo respeita essa chave. A entrega continua sendo pelo menos uma vez; esta API não torna efeitos externos exatamente uma vez, não restaura progresso de heartbeat nem implementa checkpoints retomáveis de atividade. + +Consulte os [métodos de identidade de ActivityContext](https://rust.durable-workflow.com/durable_workflow/struct.ActivityContext.html#method.activity_execution_id) e a [verificação da instalação normal 4.9.0](https://github.com/durable-workflow/sdk-rust/issues/139#issuecomment-6367230500) com controles ordinary/cooperative, locais e de sessões de worker. O contrato compartilhado está em [garantias de execução](../constraints/execution-guarantees.md#service-activity-identity). + ## Atividades locais {#local-activities} O SDK Rust 3.1.0 adiciona execução local inline em workers configurados com diff --git a/i18n/pt-BR/source-hashes.json b/i18n/pt-BR/source-hashes.json index f96f8dd692a..f3d1cd198fb 100644 --- a/i18n/pt-BR/source-hashes.json +++ b/i18n/pt-BR/source-hashes.json @@ -14,7 +14,7 @@ "configuration/publishing-config.md": "c757acd749c0d2696a6e19484249c9298dd15970ce0cf2ae0e6d2dfd82c8b6d6", "constraints/activity-constraints.md": "5a953d0e95e750b6c02d1c72b72199fb3ff4687540cebc56aa3b216cf667bb05", "constraints/constraints-summary.md": "fb48d01502388fc3821eae3790f470ed29cec91545420450f96fc77b84e589f1", - "constraints/execution-guarantees.md": "e0903f1d6d7461191f2190453f9f96ce9bdcf6811e7e99c7d51f81e2f58ef27d", + "constraints/execution-guarantees.md": "c24aaff70bfcf50366459ec698ced67adff1e02c1b0ca23c8178a13873037f5a", "constraints/idempotent-vs-deterministic.md": "f7396f01a4111ce187e751b009c1efb96f5538e8a602006eed24f7b1d8f44adf", "constraints/overview.md": "fd6c842c6c22d6f0df37a52de15ca74b34664f5ecd78af0c08b1e0cdb9a2be1f", "constraints/structural-limits.md": "3dfeac3620285f5271653c31392e26e5111fe814ece08fc44367b5786d99c47d", @@ -84,7 +84,7 @@ "polyglot/prerelease-history-migration.md": "a57f05f492228a8a67791f9152648a1e5f80856325b78777cf63b6ef49b7413c", "polyglot/python.md": "d55056ca7638df07b7267bc6d62e635b954957b99620478e861df90558860df3", "polyglot/rust-cloud-quickstart.md": "2303434fc9302a81a8381ad4836423ef9952eb3201a4574c432254e3cb68c5f3", - "polyglot/rust.md": "f6ac50f08ee1a7e94686403df5880e771cd306aa07aed69c73261e5a25f6d78f", + "polyglot/rust.md": "5ff66bcb7e5369bcffd8611342a35c27028cac5a4ee376e86d90334a2b12d365", "polyglot/server-api-reference.md": "e94af77a13b341d6fdc9941d4ee94e5053ab932d2e77069b238eb33351414e83", "polyglot/server-config-reference.md": "edb4cf00b9df2c9946b32a81c6bb2c4db6eaee89794b85286c61c235a4846414", "polyglot/server-role-topology.md": "3d048f0c6b5f179399622508f51e67fff8aa5a6d5b2492533fc720eeec2c27f2", diff --git a/i18n/uk/docusaurus-plugin-content-docs/current/constraints/execution-guarantees.md b/i18n/uk/docusaurus-plugin-content-docs/current/constraints/execution-guarantees.md index 8c3ee0b4de7..b51d48bb04e 100644 --- a/i18n/uk/docusaurus-plugin-content-docs/current/constraints/execution-guarantees.md +++ b/i18n/uk/docusaurus-plugin-content-docs/current/constraints/execution-guarantees.md @@ -137,6 +137,10 @@ final class ChargeCard extends Activity } ``` +### Ідентичність activity у service mode {#service-activity-identity} + +Для Rust activity у service mode SDK **4.9.0 або новіший** надає початкові необов’язкові `activity_execution_id()`, `workflow_id()` (екземпляр) і `run_id()` через `ActivityContext`. Використовуйте логічний ID activity протягом повторів; відсутні поля claim залишаються `None`, а ID окремого завдання чи спроби їх не замінює. [Приклад обробника Rust](../polyglot/rust.md#activity-identity) створює зовнішній ключ і пояснює обмеження старіших Server, local activities та тестів без Server. Ключ усе одно потребує ідемпотентного зовнішнього API або сталого журналу ефектів; ці методи не надають відновлюваних контрольних точок. + ## Що розробники мають зробити ідемпотентним {#what-developers-must-make-idempotent} Вам **не** потрібно робити саме відтворення workflow ідемпотентним. Фреймворк diff --git a/i18n/uk/docusaurus-plugin-content-docs/current/polyglot/rust.md b/i18n/uk/docusaurus-plugin-content-docs/current/polyglot/rust.md index f4d462e0972..fa81aa44b11 100644 --- a/i18n/uk/docusaurus-plugin-content-docs/current/polyglot/rust.md +++ b/i18n/uk/docusaurus-plugin-content-docs/current/polyglot/rust.md @@ -282,6 +282,44 @@ pub fn register_charge(worker: &mut Worker) { Local activities та прямі виклики `testing::WorkflowEnvironment::run_activity` не мають отриманого snapshot сервера й повертають невідому policy. Нові тести `run_workflow` надають змодельований snapshot, записаний у їхній згенерованій історії. Ця семантика тестів не доводить, що розгорнутий Server передає policy. Див. [ActivityRetryInfo](https://rust.durable-workflow.com/durable_workflow/struct.ActivityRetryInfo.html) та [ActivityAttemptLimit](https://rust.durable-workflow.com/durable_workflow/enum.ActivityAttemptLimit.html). +## Стала ідентичність activity та ідемпотентність зовнішніх операцій {#activity-identity} + +Rust SDK **4.9.0 або новіший** надає початкові отримані ідентифікатори через `ActivityContext`. Перевірте встановлений crate у `Cargo.lock`: окремо вибрана вище версія встановлення може бути старішою. Ці методи повертають незмінні значення `Option<&str>`, збережені з початкового claim, зокрема для activity у worker session. + +| Метод | Ідентичність і застосування | +| --- | --- | +| `activity_execution_id()` | Одне логічне виконання activity протягом повторних спроб; використовуйте для дедуплікації зовнішньої операції. | +| `workflow_id()` | ID **екземпляра** workflow-власника для бізнес-кореляції. | +| `run_id()` | ID конкретного **run** workflow-власника для кореляції цього запуску. | + +Сформуйте ключ для конкретної операції та передайте його ідемпотентному зовнішньому API або сталому журналу ефектів. Цей обробник лише створює ключ: він не списує платіж і не реалізує зовнішню дедуплікацію. Якщо ID activity відсутній, обробник відмовляє до будь-якого ефекту; застосунок натомість може надати власний явно сталий бізнес-ключ. + +```rust +use durable_workflow::{json, ActivityError, Worker}; + +pub fn register_charge(worker: &mut Worker) { + worker.register_activity("charge", |ctx, _| async move { + let execution_id = ctx.activity_execution_id().ok_or_else(|| { + ActivityError::new("MissingActivityIdentity", "Server activity identity is required") + .non_retryable(true) + })?; + // Pass this key to an idempotent downstream API or durable effect ledger. + let key = format!("payments:charge:{execution_id}"); + Ok(json!({ + "idempotency_key": key, + "workflow_id": ctx.workflow_id(), + "run_id": ctx.run_id(), + })) + }); +} +``` + +Якщо старіший Server не передає ці поля, вони залишаються `None`. Не замінюйте відсутній логічний ID activity ідентифікатором завдання чи спроби або номером спроби: під час повтору ключ зміниться. Inline local activities можуть отримувати справжні ID батьківських workflow/run, але не мають серверного ID виконання activity до запису команди сервером. Тести activity без Server не мають отриманої ідентичності claim. + +Сталий ключ запобігає дублюванню ефектів лише тоді, коли зовнішня система його враховує. Доставка activity залишається at-least-once; цей API не робить зовнішню роботу exactly-once, не відновлює прогрес heartbeat і не реалізує відновлювані контрольні точки activity. + +Див. [методи ідентичності ActivityContext](https://rust.durable-workflow.com/durable_workflow/struct.ActivityContext.html#method.activity_execution_id) та [перевірку звичайного встановлення 4.9.0](https://github.com/durable-workflow/sdk-rust/issues/139#issuecomment-6367230500) з ordinary/cooperative, local і worker-session контролями. Спільний контракт ідемпотентності описано в [гарантіях виконання](../constraints/execution-guarantees.md#service-activity-identity). + ## Локальні activity {#local-activities} Rust SDK 3.1.0 додає inline local execution на workers із налаштуванням diff --git a/i18n/uk/source-hashes.json b/i18n/uk/source-hashes.json index f96f8dd692a..f3d1cd198fb 100644 --- a/i18n/uk/source-hashes.json +++ b/i18n/uk/source-hashes.json @@ -14,7 +14,7 @@ "configuration/publishing-config.md": "c757acd749c0d2696a6e19484249c9298dd15970ce0cf2ae0e6d2dfd82c8b6d6", "constraints/activity-constraints.md": "5a953d0e95e750b6c02d1c72b72199fb3ff4687540cebc56aa3b216cf667bb05", "constraints/constraints-summary.md": "fb48d01502388fc3821eae3790f470ed29cec91545420450f96fc77b84e589f1", - "constraints/execution-guarantees.md": "e0903f1d6d7461191f2190453f9f96ce9bdcf6811e7e99c7d51f81e2f58ef27d", + "constraints/execution-guarantees.md": "c24aaff70bfcf50366459ec698ced67adff1e02c1b0ca23c8178a13873037f5a", "constraints/idempotent-vs-deterministic.md": "f7396f01a4111ce187e751b009c1efb96f5538e8a602006eed24f7b1d8f44adf", "constraints/overview.md": "fd6c842c6c22d6f0df37a52de15ca74b34664f5ecd78af0c08b1e0cdb9a2be1f", "constraints/structural-limits.md": "3dfeac3620285f5271653c31392e26e5111fe814ece08fc44367b5786d99c47d", @@ -84,7 +84,7 @@ "polyglot/prerelease-history-migration.md": "a57f05f492228a8a67791f9152648a1e5f80856325b78777cf63b6ef49b7413c", "polyglot/python.md": "d55056ca7638df07b7267bc6d62e635b954957b99620478e861df90558860df3", "polyglot/rust-cloud-quickstart.md": "2303434fc9302a81a8381ad4836423ef9952eb3201a4574c432254e3cb68c5f3", - "polyglot/rust.md": "f6ac50f08ee1a7e94686403df5880e771cd306aa07aed69c73261e5a25f6d78f", + "polyglot/rust.md": "5ff66bcb7e5369bcffd8611342a35c27028cac5a4ee376e86d90334a2b12d365", "polyglot/server-api-reference.md": "e94af77a13b341d6fdc9941d4ee94e5053ab932d2e77069b238eb33351414e83", "polyglot/server-config-reference.md": "edb4cf00b9df2c9946b32a81c6bb2c4db6eaee89794b85286c61c235a4846414", "polyglot/server-role-topology.md": "3d048f0c6b5f179399622508f51e67fff8aa5a6d5b2492533fc720eeec2c27f2", diff --git a/i18n/zh-Hans/docusaurus-plugin-content-docs/current/constraints/execution-guarantees.md b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/constraints/execution-guarantees.md index 7c9c8a50b81..554b32a9a28 100644 --- a/i18n/zh-Hans/docusaurus-plugin-content-docs/current/constraints/execution-guarantees.md +++ b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/constraints/execution-guarantees.md @@ -110,6 +110,10 @@ final class ChargeCard extends Activity } ``` +### 服务模式活动标识 {#service-activity-identity} + +Rust 服务模式活动可通过 SDK **4.9.0 或更新版本**的 `ActivityContext` 取得原始可选值 `activity_execution_id()`、`workflow_id()`(实例)和 `run_id()`。跨重试使用逻辑活动 ID;claim 缺失字段保持为 `None`,不能用每次尝试的 task/attempt ID 代替。[Rust 处理函数示例](../polyglot/rust.md#activity-identity)生成外部键,并解释旧 Server、本地活动及无 Server 测试的边界。键仍需要支持幂等性的外部 API 或持久化副作用账本;这些方法不提供可恢复检查点。 + ## 开发者需要保证哪些操作幂等 {#what-developers-must-make-idempotent} 你无需让工作流重放本身具有幂等性。框架通过已提交历史重建状态,负责处理重放。 diff --git a/i18n/zh-Hans/docusaurus-plugin-content-docs/current/polyglot/rust.md b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/polyglot/rust.md index b659921f2f4..c7929fb34f0 100644 --- a/i18n/zh-Hans/docusaurus-plugin-content-docs/current/polyglot/rust.md +++ b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/polyglot/rust.md @@ -229,6 +229,44 @@ pub fn register_charge(worker: &mut Worker) { 本地活动和直接调用 `testing::WorkflowEnvironment::run_activity` 没有收到的 Server 快照,会报告未知策略。新的 `run_workflow` 测试公开其生成历史中记录的模型快照。这些测试语义不能证明已部署 Server 会发送策略。参见 [ActivityRetryInfo](https://rust.durable-workflow.com/durable_workflow/struct.ActivityRetryInfo.html) 和 [ActivityAttemptLimit](https://rust.durable-workflow.com/durable_workflow/enum.ActivityAttemptLimit.html)。 +## 稳定的活动标识与外部操作幂等性 {#activity-identity} + +Rust SDK **4.9.0 或更新版本**通过 `ActivityContext` 提供最初收到的标识。请检查 `Cargo.lock` 中实际安装的 crate;上方独立选择的安装版本可能更旧。这些方法返回从原始 claim 保存的不可变 `Option<&str>`,也适用于 worker session 活动。 + +| 方法 | 标识及用途 | +| --- | --- | +| `activity_execution_id()` | 跨重试保持同一逻辑活动执行的标识;用于外部操作去重。 | +| `workflow_id()` | 所属工作流的**实例** ID;用于业务关联。 | +| `run_id()` | 所属工作流的 **run** ID;用于关联这一次运行。 | + +为特定操作生成键,并传给支持幂等性的外部 API 或持久化副作用账本。此处理函数只生成键,不执行扣款,也不实现外部去重。如果缺少活动标识,它会在任何副作用发生前拒绝;应用也可以显式提供自己的稳定业务键。 + +```rust +use durable_workflow::{json, ActivityError, Worker}; + +pub fn register_charge(worker: &mut Worker) { + worker.register_activity("charge", |ctx, _| async move { + let execution_id = ctx.activity_execution_id().ok_or_else(|| { + ActivityError::new("MissingActivityIdentity", "Server activity identity is required") + .non_retryable(true) + })?; + // Pass this key to an idempotent downstream API or durable effect ledger. + let key = format!("payments:charge:{execution_id}"); + Ok(json!({ + "idempotency_key": key, + "workflow_id": ctx.workflow_id(), + "run_id": ctx.run_id(), + })) + }); +} +``` + +旧 Server 省略这些字段时,它们保持为 `None`。不要用每次尝试的 task ID、attempt ID 或尝试次数代替缺失的逻辑活动 ID,否则重试时键会改变。内联本地活动可以收到真实的父工作流/run ID,但在 Server 记录其命令前,没有 Server 活动执行 ID。不使用 Server 的活动测试也没有收到的 claim 标识。 + +只有外部系统遵守此键时,稳定键才能用于防止重复副作用。活动仍是至少一次投递;此 API 不会使外部操作恰好一次,不会恢复 heartbeat 进度,也不提供可恢复的活动检查点。 + +请参阅 [ActivityContext 标识方法](https://rust.durable-workflow.com/durable_workflow/struct.ActivityContext.html#method.activity_execution_id)及包含 ordinary/cooperative、本地和 worker-session 验证的[正常安装 4.9.0 记录](https://github.com/durable-workflow/sdk-rust/issues/139#issuecomment-6367230500)。共享幂等性契约见[执行保证](../constraints/execution-guarantees.md#service-activity-identity)。 + ## 本地活动 {#local-activities} Rust SDK 3.1.0 在配置了 `Worker::local_activities(true)` 的 Worker 上增加内联本地执行。使用普通活动注册方法注册回调,然后使用工作流上下文的本地活动方法。重试和超时配置见[可运行示例](https://github.com/durable-workflow/sdk-rust/blob/3.1.0/examples/local_activities.rs)及 [LocalActivityOptions 参考](https://rust.durable-workflow.com/durable_workflow/struct.LocalActivityOptions.html)。 diff --git a/i18n/zh-Hans/source-hashes.json b/i18n/zh-Hans/source-hashes.json index f96f8dd692a..f3d1cd198fb 100644 --- a/i18n/zh-Hans/source-hashes.json +++ b/i18n/zh-Hans/source-hashes.json @@ -14,7 +14,7 @@ "configuration/publishing-config.md": "c757acd749c0d2696a6e19484249c9298dd15970ce0cf2ae0e6d2dfd82c8b6d6", "constraints/activity-constraints.md": "5a953d0e95e750b6c02d1c72b72199fb3ff4687540cebc56aa3b216cf667bb05", "constraints/constraints-summary.md": "fb48d01502388fc3821eae3790f470ed29cec91545420450f96fc77b84e589f1", - "constraints/execution-guarantees.md": "e0903f1d6d7461191f2190453f9f96ce9bdcf6811e7e99c7d51f81e2f58ef27d", + "constraints/execution-guarantees.md": "c24aaff70bfcf50366459ec698ced67adff1e02c1b0ca23c8178a13873037f5a", "constraints/idempotent-vs-deterministic.md": "f7396f01a4111ce187e751b009c1efb96f5538e8a602006eed24f7b1d8f44adf", "constraints/overview.md": "fd6c842c6c22d6f0df37a52de15ca74b34664f5ecd78af0c08b1e0cdb9a2be1f", "constraints/structural-limits.md": "3dfeac3620285f5271653c31392e26e5111fe814ece08fc44367b5786d99c47d", @@ -84,7 +84,7 @@ "polyglot/prerelease-history-migration.md": "a57f05f492228a8a67791f9152648a1e5f80856325b78777cf63b6ef49b7413c", "polyglot/python.md": "d55056ca7638df07b7267bc6d62e635b954957b99620478e861df90558860df3", "polyglot/rust-cloud-quickstart.md": "2303434fc9302a81a8381ad4836423ef9952eb3201a4574c432254e3cb68c5f3", - "polyglot/rust.md": "f6ac50f08ee1a7e94686403df5880e771cd306aa07aed69c73261e5a25f6d78f", + "polyglot/rust.md": "5ff66bcb7e5369bcffd8611342a35c27028cac5a4ee376e86d90334a2b12d365", "polyglot/server-api-reference.md": "e94af77a13b341d6fdc9941d4ee94e5053ab932d2e77069b238eb33351414e83", "polyglot/server-config-reference.md": "edb4cf00b9df2c9946b32a81c6bb2c4db6eaee89794b85286c61c235a4846414", "polyglot/server-role-topology.md": "3d048f0c6b5f179399622508f51e67fff8aa5a6d5b2492533fc720eeec2c27f2", From 39e83f03be3c014119bd9bee019bc5219ed20694 Mon Sep 17 00:00:00 2001 From: Durable Workflow Date: Fri, 23 Oct 2026 14:51:31 +0000 Subject: [PATCH 2/2] docs: correct spacing in German installed receipt link --- i18n/de/docusaurus-plugin-content-docs/current/polyglot/rust.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/de/docusaurus-plugin-content-docs/current/polyglot/rust.md b/i18n/de/docusaurus-plugin-content-docs/current/polyglot/rust.md index a19b9fb7496..7974d1cf57b 100644 --- a/i18n/de/docusaurus-plugin-content-docs/current/polyglot/rust.md +++ b/i18n/de/docusaurus-plugin-content-docs/current/polyglot/rust.md @@ -318,7 +318,7 @@ Lässt ein älterer Server diese Felder aus, bleiben sie `None`. Ersetzen Sie ei Ein stabiler Schlüssel ermöglicht die Vermeidung doppelter Effekte nur, wenn das externe System ihn beachtet. Die Zustellung bleibt mindestens einmal; diese API macht externe Effekte nicht genau einmal, stellt keinen Heartbeat-Fortschritt wieder her und implementiert keine fortsetzbaren Aktivitäts-Checkpoints. -Siehe die [Identitätsmethoden von ActivityContext](https://rust.durable-workflow.com/durable_workflow/struct.ActivityContext.html#method.activity_execution_id) und die [Prüfung der normalen Installation4.9.0](https://github.com/durable-workflow/sdk-rust/issues/139#issuecomment-6367230500) mit Ordinary-/Cooperative-, Local- und Worker-Session-Kontrollen. Der gemeinsame Vertrag steht unter [Ausführungsgarantien](../constraints/execution-guarantees.md#service-activity-identity). +Siehe die [Identitätsmethoden von ActivityContext](https://rust.durable-workflow.com/durable_workflow/struct.ActivityContext.html#method.activity_execution_id) und die [Prüfung der normalen Installation 4.9.0](https://github.com/durable-workflow/sdk-rust/issues/139#issuecomment-6367230500) mit Ordinary-/Cooperative-, Local- und Worker-Session-Kontrollen. Der gemeinsame Vertrag steht unter [Ausführungsgarantien](../constraints/execution-guarantees.md#service-activity-identity). ## Lokale Aktivitäten {#local-activities}