Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/constraints/execution-guarantees.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
38 changes: 38 additions & 0 deletions docs/polyglot/rust.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
38 changes: 38 additions & 0 deletions i18n/de/docusaurus-plugin-content-docs/current/polyglot/rust.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 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}

Rust SDK 3.1.0 ergänzt lokale Inline-Ausführung auf Workern mit
Expand Down
4 changes: 2 additions & 2 deletions i18n/de/source-hashes.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
38 changes: 38 additions & 0 deletions i18n/es/docusaurus-plugin-content-docs/current/polyglot/rust.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
4 changes: 2 additions & 2 deletions i18n/es/source-hashes.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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é.
Expand Down
Loading
Loading