diff --git a/docs/constraints/execution-guarantees.md b/docs/constraints/execution-guarantees.md index 5275a14e301..74dff4ac3cf 100644 --- a/docs/constraints/execution-guarantees.md +++ b/docs/constraints/execution-guarantees.md @@ -142,6 +142,18 @@ final class ChargeCard extends Activity 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. +Python service-mode activities expose the read-only optional +`activity.context().info.activity_execution_id`, with `workflow_id` and `run_id` +for the owning workflow instance and run. Use the logical execution ID across +retries. Missing identity stays `None`; never substitute a task, attempt or +session ID. The [Python identity guide](../polyglot/python.md#activity-identity) +links the SDK-owned service example and defines legacy, session, prepared-local, +inline-local and Server-free behavior. Its named published-package/native +Server receipt proves ordinary retry identity only. The ID is public metadata, +not claim authority, and does not make an external effect exactly once. Keep +downstream idempotency, distinct keys for different effects and outcome +reconciliation. + ## What Developers Must Make Idempotent You do **not** need to make workflow replay itself idempotent. The framework diff --git a/docs/polyglot/python.md b/docs/polyglot/python.md index 1c85b2e8d29..900cb4fb7ba 100644 --- a/docs/polyglot/python.md +++ b/docs/polyglot/python.md @@ -1158,6 +1158,36 @@ async def long_running_task(items: list) -> dict: return {"processed": len(items)} ``` +#### Logical activity execution identity {#activity-identity} + +Python SDK 2.15.0 and later expose the read-only optional +`activity.context().info.activity_execution_id`. It identifies one logical +activity execution across retries. `info.workflow_id` and `info.run_id` +identify its owning workflow instance and run. Use the logical execution ID +for an external service's idempotency key. Task IDs and attempt IDs change +on retry and must not replace it. + +Missing, invalid or blank execution IDs remain `None`, including on older +claims. Nonblank received strings retain their exact spelling. If an operation +requires this key, refuse it before performing the external effect when the +ID is unavailable. Session-routed activities use their ordinary claim identity. +Prepared local activities use their validated admission receipt's execution +ID. Inline local activities have no admitted execution ID and expose `None`, +while retaining parent workflow/run IDs. Server-free mocks do not create +Server activity identity. + +Use the SDK's [idempotency-key helper and activity identity guide](https://python.durable-workflow.com/sdk-reference/#activity-execution-identity) +for the service-mode example. Give different external operations stable +operation suffixes, and ensure the downstream service honors the key. An +execution ID is public metadata, not proof of a live claim or authorization +for an external effect. Keep credentials, current-attempt fencing and outcome +reconciliation. The [published-package ordinary retry receipt](https://github.com/durable-workflow/.github/issues/211#issuecomment-6869562527) +binds Python SDK 2.17.2 to native Server 3.9.2. It proves a stable logical +execution/workflow/run identity and distinct task/attempt IDs across attempts +1 and 2. Local and session behavior retain their separately defined scope. +See [execution guarantees](../constraints/execution-guarantees.md#service-activity-identity) +for the shared idempotency contract. + #### Received retry policy and original attempt {#activity-retry-metadata} Requires Python SDK **2.12.0 or later**. `info = activity.context().info` 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 8d1abd2cc1a..d7a7727eb80 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 @@ -114,6 +114,20 @@ final class ChargeCard extends Activity 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. +Python-Aktivitäten im Dienstmodus stellen das schreibgeschützte optionale Feld +`activity.context().info.activity_execution_id` sowie `workflow_id` und `run_id` +für die zugehörige Workflow-Instanz und den Run bereit. Verwenden Sie die +logische Ausführungs-ID über Wiederholungen hinweg. Fehlende Identität bleibt +`None`. Ersetzen Sie sie niemals durch eine Task-, Versuchs- oder Sitzungs-ID. +Der [Python-Identitätsleitfaden](../polyglot/python.md#activity-identity) verlinkt +das Dienstmodus-Beispiel des SDKs und definiert das Verhalten älterer Claims, +von Sitzungen, vorbereiteten und inline ausgeführten lokalen Aktivitäten sowie +Tests ohne Server. Sein benannter Beleg mit veröffentlichtem Paket und nativem +Server belegt nur die Identität bei gewöhnlichen Wiederholungen. Die ID ist +öffentliche Metainformation, keine Claim-Autorität, und macht einen externen Effekt +nicht Exactly-once. Behalten Sie nachgelagerte Idempotenz, unterschiedliche +Schlüssel für verschiedene Effekte und Ergebnisabgleich bei. + ## 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/python.md b/i18n/de/docusaurus-plugin-content-docs/current/polyglot/python.md index f460c8c0a9c..0c2bc38cc1a 100644 --- a/i18n/de/docusaurus-plugin-content-docs/current/polyglot/python.md +++ b/i18n/de/docusaurus-plugin-content-docs/current/polyglot/python.md @@ -1110,6 +1110,41 @@ async def long_running_task(items: list) -> dict: return {"processed": len(items)} ``` +#### Logische Aktivitätsausführung identifizieren {#activity-identity} + +Python SDK 2.15.0 und neuer stellen das schreibgeschützte optionale Feld +`activity.context().info.activity_execution_id` bereit. Es identifiziert eine +logische Aktivitätsausführung über Wiederholungen hinweg. `info.workflow_id` +und `info.run_id` identifizieren die zugehörige Workflow-Instanz und den Run. +Verwenden Sie die logische Ausführungs-ID als Idempotenzschlüssel für einen +externen Dienst. Task-IDs und Versuchs-IDs ändern sich bei einer Wiederholung +und dürfen sie nicht ersetzen. + +Fehlende, ungültige oder leere Ausführungs-IDs bleiben `None`, auch bei älteren +Claims. Empfangene Zeichenfolgen mit mindestens einem Nicht-Leerzeichen +behalten ihre exakte Schreibweise. Wenn eine Operation diesen Schlüssel +benötigt, lehnen Sie sie bei fehlender ID vor dem externen Effekt ab. +Sitzungsgebundene Aktivitäten verwenden die Identität ihres gewöhnlichen Claims. +Vorbereitete lokale Aktivitäten verwenden die Ausführungs-ID ihres validierten +Zulassungsbelegs. Inline ausgeführte lokale Aktivitäten besitzen keine +zugelassene Ausführungs-ID und liefern `None`, behalten aber die IDs ihres +übergeordneten Workflows und Runs. Mocks ohne Server erzeugen keine +Server-Aktivitätsidentität. + +Das Dienstmodus-Beispiel finden Sie im [SDK-Leitfaden mit Idempotenzschlüssel-Helfer und Aktivitätsidentität](https://python.durable-workflow.com/sdk-reference/#activity-execution-identity). +Geben Sie verschiedenen externen Operationen stabile Operationssuffixe und +stellen Sie sicher, dass der nachgelagerte Dienst den Schlüssel berücksichtigt. +Eine Ausführungs-ID ist öffentliche Metainformation, kein Nachweis eines aktiven +Claims und keine Berechtigung für einen externen Effekt. Behalten Sie +Zugangsdaten, Fencing des aktuellen Versuchs und Ergebnisabgleich bei. Der +[Beleg für gewöhnliche Wiederholungen mit dem veröffentlichten Paket](https://github.com/durable-workflow/.github/issues/211#issuecomment-6869562527) +bindet Python SDK 2.17.2 an den nativen Server 3.9.2. Er belegt stabile +logische Ausführungs-, Workflow- und Run-Identität sowie unterschiedliche +Task- und Versuchs-IDs für die Versuche 1 und 2. Lokales und Sitzungsverhalten +behalten ihren gesondert definierten Geltungsbereich. Siehe +[Ausführungsgarantien](../constraints/execution-guarantees.md#service-activity-identity) +für den gemeinsamen Idempotenzvertrag. + #### Empfangene Wiederholungsrichtlinie und ursprünglicher Versuch {#activity-retry-metadata} Erfordert Python SDK **2.12.0 oder neuer**. `info = activity.context().info` diff --git a/i18n/de/source-hashes.json b/i18n/de/source-hashes.json index 094463e2c6f..045eb71aa6f 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": "c24aaff70bfcf50366459ec698ced67adff1e02c1b0ca23c8178a13873037f5a", + "constraints/execution-guarantees.md": "9e53840c400b14186587714b32dd54dd780aaa68f2a132fc1e4e4d1f3eeadd0b", "constraints/idempotent-vs-deterministic.md": "f7396f01a4111ce187e751b009c1efb96f5538e8a602006eed24f7b1d8f44adf", "constraints/overview.md": "fd6c842c6c22d6f0df37a52de15ca74b34664f5ecd78af0c08b1e0cdb9a2be1f", "constraints/structural-limits.md": "5c7b7f6c86c5ca547eb3f200400ceab3b589f32d83866914f44e3a5a7d81e964", @@ -84,7 +84,7 @@ "polyglot/polling-patterns.md": "30875099a23731c6c471b481a771378acc6ff57eed2fda4405a509057534c989", "polyglot/portable-worker-affinity.md": "40973c6a31a76845b4f95e9a505e68ad76abd5174bbdccf37993cdebc8904959", "polyglot/prerelease-history-migration.md": "a57f05f492228a8a67791f9152648a1e5f80856325b78777cf63b6ef49b7413c", - "polyglot/python.md": "82da06617fe24e70c5c89197d192a81430a282b788ef93afd3b3bcb690ba2a9f", + "polyglot/python.md": "57734052d6ffae8d660083626bf47fb7c392c492ab0581a8942401046bb25d38", "polyglot/runtime-migration.md": "5a78713bb8cb74aea58f6d5d826400d968a405f69c6ff17fdf2f7decb1d14b71", "polyglot/rust-cloud-quickstart.md": "2303434fc9302a81a8381ad4836423ef9952eb3201a4574c432254e3cb68c5f3", "polyglot/rust.md": "31950634b8ccdb5c288ba871cc7f816de6683c52bf738bfdc13fa7aa825c6335", 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 3c9813b8757..472f9473100 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 @@ -143,6 +143,20 @@ final class ChargeCard extends Activity 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. +Las actividades Python en modo servicio exponen el campo opcional de solo +lectura `activity.context().info.activity_execution_id`, con `workflow_id` y +`run_id` para la instancia de workflow y la ejecución a las que pertenecen. +Use el ID de ejecución lógica a través de los reintentos. Una identidad ausente +sigue siendo `None`. Nunca la sustituya por un ID de tarea, intento o sesión. +La [guía de identidad de Python](../polyglot/python.md#activity-identity) enlaza +el ejemplo de modo servicio mantenido por el SDK y define el comportamiento +de claims antiguos, sesiones, actividades locales preparadas, actividades +locales inline y contextos sin Server. Su recibo con el paquete publicado y +Server nativo solo demuestra identidad en reintentos ordinarios. El ID es +metadato público, no autoridad del claim, y no hace que un efecto externo ocurra +exactamente una vez. Mantenga la idempotencia del destino, claves distintas +para efectos diferentes y reconciliación de resultados. + ## 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/python.md b/i18n/es/docusaurus-plugin-content-docs/current/polyglot/python.md index 0b923ba68c9..717f369f800 100644 --- a/i18n/es/docusaurus-plugin-content-docs/current/polyglot/python.md +++ b/i18n/es/docusaurus-plugin-content-docs/current/polyglot/python.md @@ -1086,6 +1086,40 @@ async def long_running_task(items: list) -> dict: return {"processed": len(items)} ``` +#### Identidad de la ejecución lógica de una actividad {#activity-identity} + +Python SDK 2.15.0 y posteriores exponen el campo opcional de solo lectura +`activity.context().info.activity_execution_id`. Identifica una ejecución +lógica de actividad a través de sus reintentos. `info.workflow_id` e +`info.run_id` identifican la instancia de workflow y la ejecución a las que +pertenece. Use el ID de ejecución lógica como clave de idempotencia del +servicio externo. Los ID de tarea y de intento cambian al reintentar y no +deben sustituirlo. + +Los ID de ejecución ausentes, no válidos o en blanco siguen siendo `None`, +también en claims antiguos. Las cadenas recibidas que no están en blanco +conservan su escritura exacta. Si una operación requiere esta clave, rechácela +antes del efecto externo cuando el ID no esté disponible. Las actividades +dirigidas a una sesión usan la identidad de su claim ordinario. Las actividades +locales preparadas usan el ID de ejecución de su recibo de admisión validado. +Las actividades locales inline no tienen un ID de ejecución admitido y exponen +`None`, aunque conservan los ID del workflow y de la ejecución padre. Los mocks +sin Server no crean identidad de actividad de Server. + +Consulte el ejemplo de modo servicio en la [guía del SDK sobre el helper de claves de idempotencia y la identidad de actividad](https://python.durable-workflow.com/sdk-reference/#activity-execution-identity). +Asigne sufijos de operación estables a las distintas operaciones externas y +asegúrese de que el servicio de destino respeta la clave. Un ID de ejecución +es metadato público, no una prueba de un claim activo ni una autorización para +un efecto externo. Mantenga las credenciales, el fencing del intento actual +y la reconciliación de resultados. El [recibo de reintento ordinario con el paquete publicado](https://github.com/durable-workflow/.github/issues/211#issuecomment-6869562527) +vincula Python SDK 2.17.2 con Server nativo 3.9.2. Demuestra que los ID de +ejecución lógica de actividad, instancia de workflow y ejecución de workflow +se mantienen estables, mientras los ID de tarea y de intento son distintos +entre los intentos 1 y 2. El comportamiento local y de +sesión mantiene su alcance definido por separado. Consulte las +[garantías de ejecución](../constraints/execution-guarantees.md#service-activity-identity) +para el contrato de idempotencia compartido. + #### Política de reintentos recibida e intento original {#activity-retry-metadata} Requiere Python SDK **2.12.0 o posterior**. `info = activity.context().info` diff --git a/i18n/es/source-hashes.json b/i18n/es/source-hashes.json index 094463e2c6f..045eb71aa6f 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": "c24aaff70bfcf50366459ec698ced67adff1e02c1b0ca23c8178a13873037f5a", + "constraints/execution-guarantees.md": "9e53840c400b14186587714b32dd54dd780aaa68f2a132fc1e4e4d1f3eeadd0b", "constraints/idempotent-vs-deterministic.md": "f7396f01a4111ce187e751b009c1efb96f5538e8a602006eed24f7b1d8f44adf", "constraints/overview.md": "fd6c842c6c22d6f0df37a52de15ca74b34664f5ecd78af0c08b1e0cdb9a2be1f", "constraints/structural-limits.md": "5c7b7f6c86c5ca547eb3f200400ceab3b589f32d83866914f44e3a5a7d81e964", @@ -84,7 +84,7 @@ "polyglot/polling-patterns.md": "30875099a23731c6c471b481a771378acc6ff57eed2fda4405a509057534c989", "polyglot/portable-worker-affinity.md": "40973c6a31a76845b4f95e9a505e68ad76abd5174bbdccf37993cdebc8904959", "polyglot/prerelease-history-migration.md": "a57f05f492228a8a67791f9152648a1e5f80856325b78777cf63b6ef49b7413c", - "polyglot/python.md": "82da06617fe24e70c5c89197d192a81430a282b788ef93afd3b3bcb690ba2a9f", + "polyglot/python.md": "57734052d6ffae8d660083626bf47fb7c392c492ab0581a8942401046bb25d38", "polyglot/runtime-migration.md": "5a78713bb8cb74aea58f6d5d826400d968a405f69c6ff17fdf2f7decb1d14b71", "polyglot/rust-cloud-quickstart.md": "2303434fc9302a81a8381ad4836423ef9952eb3201a4574c432254e3cb68c5f3", "polyglot/rust.md": "31950634b8ccdb5c288ba871cc7f816de6683c52bf738bfdc13fa7aa825c6335", 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 422ada0c330..00671feb27c 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 @@ -114,6 +114,20 @@ final class ChargeCard extends Activity 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. +Les activités Python en mode service exposent le champ facultatif en lecture +seule `activity.context().info.activity_execution_id`, avec `workflow_id` et +`run_id` pour l’instance de workflow et le run auxquels elles appartiennent. +Utilisez l’identifiant d’exécution logique à travers les nouvelles tentatives. +Une identité absente reste `None`. Ne la remplacez jamais par un identifiant +de tâche, de tentative ou de session. Le [guide d’identité Python](../polyglot/python.md#activity-identity) +renvoie à l’exemple en mode service du SDK et définit les anciens claims, les +sessions, les activités locales préparées, les activités locales inline et les +contextes sans Server. Son reçu avec paquet publié et Server natif prouve +uniquement l’identité des nouvelles tentatives ordinaires. L’identifiant est +une métadonnée publique, pas une autorité de claim, et ne garantit pas qu’un +effet externe se produise exactement une fois. Conservez l’idempotence du destinataire, des +clés distinctes pour des effets différents et la réconciliation des résultats. + ## 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/python.md b/i18n/fr/docusaurus-plugin-content-docs/current/polyglot/python.md index 299de36097c..51044c2d2a1 100644 --- a/i18n/fr/docusaurus-plugin-content-docs/current/polyglot/python.md +++ b/i18n/fr/docusaurus-plugin-content-docs/current/polyglot/python.md @@ -1110,6 +1110,40 @@ async def long_running_task(items: list) -> dict: return {"processed": len(items)} ``` +#### Identité de l’exécution logique d’une activité {#activity-identity} + +Python SDK 2.15.0 et les versions suivantes exposent le champ facultatif en +lecture seule `activity.context().info.activity_execution_id`. Il identifie +une exécution logique d’activité à travers ses nouvelles tentatives. +`info.workflow_id` et `info.run_id` identifient l’instance de workflow et le run +auxquels elle appartient. Utilisez cet identifiant logique comme clé +d’idempotence du service externe. Les identifiants de tâche et de tentative +changent lors d’une nouvelle tentative et ne doivent pas le remplacer. + +Les identifiants d’exécution absents, invalides ou blancs restent `None`, y +compris dans les anciens claims. Les chaînes reçues non blanches conservent +leur forme exacte. Si une opération exige cette clé, refusez-la avant l’effet +externe lorsque l’identifiant est indisponible. Les activités acheminées vers +une session utilisent l’identité de leur claim ordinaire. Les activités locales +préparées utilisent l’identifiant d’exécution de leur reçu d’admission validé. +Les activités locales inline n’ont pas d’identifiant d’exécution admis et +exposent `None`, tout en conservant les identifiants du workflow et du run +parents. Les mocks sans Server ne créent pas d’identité d’activité Server. + +L’exemple en mode service se trouve dans le [guide du SDK sur le helper de clé d’idempotence et l’identité d’activité](https://python.durable-workflow.com/sdk-reference/#activity-execution-identity). +Attribuez des suffixes d’opération stables aux différentes opérations externes +et vérifiez que le service destinataire respecte la clé. Un identifiant +d’exécution est une métadonnée publique, pas une preuve d’un claim actif ni +une autorisation d’effet externe. Conservez les identifiants d’accès, le +fencing de la tentative courante et la réconciliation des résultats. Le +[reçu de nouvelle tentative ordinaire avec le paquet publié](https://github.com/durable-workflow/.github/issues/211#issuecomment-6869562527) +lie Python SDK 2.17.2 à Server natif 3.9.2. Il prouve une identité logique +d’exécution, de workflow et de run stable, avec des identifiants de tâche et +de tentative distincts entre les tentatives 1 et 2. Les comportements locaux +et de session gardent leur portée définie séparément. Consultez les +[garanties d’exécution](../constraints/execution-guarantees.md#service-activity-identity) +pour le contrat d’idempotence commun. + #### Politique de reprise reçue et tentative initiale {#activity-retry-metadata} Nécessite Python SDK **2.12.0 ou ultérieur**. `info = activity.context().info` diff --git a/i18n/fr/source-hashes.json b/i18n/fr/source-hashes.json index 094463e2c6f..045eb71aa6f 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": "c24aaff70bfcf50366459ec698ced67adff1e02c1b0ca23c8178a13873037f5a", + "constraints/execution-guarantees.md": "9e53840c400b14186587714b32dd54dd780aaa68f2a132fc1e4e4d1f3eeadd0b", "constraints/idempotent-vs-deterministic.md": "f7396f01a4111ce187e751b009c1efb96f5538e8a602006eed24f7b1d8f44adf", "constraints/overview.md": "fd6c842c6c22d6f0df37a52de15ca74b34664f5ecd78af0c08b1e0cdb9a2be1f", "constraints/structural-limits.md": "5c7b7f6c86c5ca547eb3f200400ceab3b589f32d83866914f44e3a5a7d81e964", @@ -84,7 +84,7 @@ "polyglot/polling-patterns.md": "30875099a23731c6c471b481a771378acc6ff57eed2fda4405a509057534c989", "polyglot/portable-worker-affinity.md": "40973c6a31a76845b4f95e9a505e68ad76abd5174bbdccf37993cdebc8904959", "polyglot/prerelease-history-migration.md": "a57f05f492228a8a67791f9152648a1e5f80856325b78777cf63b6ef49b7413c", - "polyglot/python.md": "82da06617fe24e70c5c89197d192a81430a282b788ef93afd3b3bcb690ba2a9f", + "polyglot/python.md": "57734052d6ffae8d660083626bf47fb7c392c492ab0581a8942401046bb25d38", "polyglot/runtime-migration.md": "5a78713bb8cb74aea58f6d5d826400d968a405f69c6ff17fdf2f7decb1d14b71", "polyglot/rust-cloud-quickstart.md": "2303434fc9302a81a8381ad4836423ef9952eb3201a4574c432254e3cb68c5f3", "polyglot/rust.md": "31950634b8ccdb5c288ba871cc7f816de6683c52bf738bfdc13fa7aa825c6335", 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 bac4c362f29..df414a9adec 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 @@ -114,6 +114,18 @@ final class ChargeCard extends Activity 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 を提供しません。 +Python のサービスモードのアクティビティは、読み取り専用の省略可能な +`activity.context().info.activity_execution_id` と、所属するワークフローインスタンス +および実行を示す `workflow_id` と `run_id` を公開します。再試行をまたいで論理実行 +ID を使ってください。ID がない場合は `None` のままです。タスク、試行、セッションの +ID で代用してはいけません。[Python の ID ガイド](../polyglot/python.md#activity-identity) +は SDK が管理するサービスモードの例にリンクし、古い claim、セッション、準備済み +ローカル、インラインのローカル、Server を使わない場合の動作を定義します。そこで +示す公開パッケージとネイティブ Server のレシートが証明するのは、通常の再試行の +ID だけです。ID は公開メタデータであり claim の権限ではなく、外部への副作用を +厳密に 1 回にするものでもありません。外部サービスの冪等性、異なる副作用ごとの +別々のキー、結果の照合を維持してください。 + ## 開発者が冪等にする処理 {#what-developers-must-make-idempotent} ワークフローのリプレイ自体を冪等にする必要はありません。フレームワークが確定済み履歴から状態を再構築して処理します。 diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/polyglot/python.md b/i18n/ja/docusaurus-plugin-content-docs/current/polyglot/python.md index 4e3a22f854f..70bbeeda538 100644 --- a/i18n/ja/docusaurus-plugin-content-docs/current/polyglot/python.md +++ b/i18n/ja/docusaurus-plugin-content-docs/current/polyglot/python.md @@ -913,6 +913,36 @@ async def long_running_task(items: list) -> dict: return {"processed": len(items)} ``` +#### アクティビティの論理実行 ID {#activity-identity} + +Python SDK 2.15.0 以降は、読み取り専用の省略可能な +`activity.context().info.activity_execution_id` を公開します。これは再試行をまたぐ +1 つの論理アクティビティ実行を識別します。`info.workflow_id` と `info.run_id` は、 +その実行が属するワークフローインスタンスと実行を識別します。外部サービスの +冪等性キーには論理実行 ID を使ってください。タスク ID と試行 ID は再試行時に +変わるため、代わりには使えません。 + +実行 ID が欠落、無効、空白のみの場合は、古い claim も含めて `None` のままです。 +受信した空白以外の文字を含む文字列は、その表記を正確に保持します。操作にこの +キーが必要で ID を利用できない場合は、外部への副作用を実行する前に拒否して +ください。セッション経由のアクティビティは通常の claim の ID を使います。 +準備済みローカルアクティビティは、検証済み受理レシートの実行 ID を使います。 +インラインのローカルアクティビティには受理済みの実行 ID がなく、`None` を公開 +しますが、親ワークフローと実行の ID は保持します。Server を使わないモックは +Server のアクティビティ ID を作りません。 + +サービスモードの例は、SDK の[冪等性キーヘルパーとアクティビティ ID のガイド](https://python.durable-workflow.com/sdk-reference/#activity-execution-identity) +を参照してください。異なる外部操作には安定した操作サフィックスを付け、外部 +サービスがキーを尊重することを確認します。実行 ID は公開メタデータであり、有効な +claim の証明でも外部への副作用の認可でもありません。認証情報、現在の試行の +fencing、結果の照合を維持してください。[公開パッケージによる通常の再試行のレシート](https://github.com/durable-workflow/.github/issues/211#issuecomment-6869562527) +は Python SDK 2.17.2 とネイティブ Server 3.9.2 を結び付けています。この証拠は、 +試行 1 と 2 の間で論理アクティビティ実行 ID、ワークフロー ID、ワークフロー実行 ID +が同じで、タスク ID と試行 ID +が異なることを示します。ローカル動作とセッション動作の範囲は別途定義されたままです。 +共通の冪等性契約は[実行保証](../constraints/execution-guarantees.md#service-activity-identity) +を参照してください。 + #### 受信した再試行ポリシーと元の試行回数 {#activity-retry-metadata} Python SDK **2.12.0 以降**が必要です。`info = activity.context().info` は diff --git a/i18n/ja/source-hashes.json b/i18n/ja/source-hashes.json index 094463e2c6f..045eb71aa6f 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": "c24aaff70bfcf50366459ec698ced67adff1e02c1b0ca23c8178a13873037f5a", + "constraints/execution-guarantees.md": "9e53840c400b14186587714b32dd54dd780aaa68f2a132fc1e4e4d1f3eeadd0b", "constraints/idempotent-vs-deterministic.md": "f7396f01a4111ce187e751b009c1efb96f5538e8a602006eed24f7b1d8f44adf", "constraints/overview.md": "fd6c842c6c22d6f0df37a52de15ca74b34664f5ecd78af0c08b1e0cdb9a2be1f", "constraints/structural-limits.md": "5c7b7f6c86c5ca547eb3f200400ceab3b589f32d83866914f44e3a5a7d81e964", @@ -84,7 +84,7 @@ "polyglot/polling-patterns.md": "30875099a23731c6c471b481a771378acc6ff57eed2fda4405a509057534c989", "polyglot/portable-worker-affinity.md": "40973c6a31a76845b4f95e9a505e68ad76abd5174bbdccf37993cdebc8904959", "polyglot/prerelease-history-migration.md": "a57f05f492228a8a67791f9152648a1e5f80856325b78777cf63b6ef49b7413c", - "polyglot/python.md": "82da06617fe24e70c5c89197d192a81430a282b788ef93afd3b3bcb690ba2a9f", + "polyglot/python.md": "57734052d6ffae8d660083626bf47fb7c392c492ab0581a8942401046bb25d38", "polyglot/runtime-migration.md": "5a78713bb8cb74aea58f6d5d826400d968a405f69c6ff17fdf2f7decb1d14b71", "polyglot/rust-cloud-quickstart.md": "2303434fc9302a81a8381ad4836423ef9952eb3201a4574c432254e3cb68c5f3", "polyglot/rust.md": "31950634b8ccdb5c288ba871cc7f816de6683c52bf738bfdc13fa7aa825c6335", 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 89ced36482b..880bd467faa 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 @@ -114,6 +114,20 @@ final class ChargeCard extends Activity 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. +Atividades Python em modo serviço expõem o campo opcional somente leitura +`activity.context().info.activity_execution_id`, com `workflow_id` e `run_id` +para a instância de workflow e a execução às quais pertencem. Use o ID da +execução lógica entre tentativas. A identidade ausente continua sendo `None`. +Nunca a substitua por um ID de tarefa, tentativa ou sessão. O +[guia de identidade do Python](../polyglot/python.md#activity-identity) aponta +para o exemplo de modo serviço mantido pelo SDK e define o comportamento de +claims antigos, sessões, atividades locais preparadas, atividades locais +inline e contextos sem Server. Seu recibo com pacote publicado e Server +nativo comprova apenas a identidade em tentativas comuns. O ID é metadado +público, não autoridade do claim, e não faz um efeito externo ocorrer +exatamente uma vez. Mantenha a idempotência do destino, chaves distintas +para efeitos diferentes e reconciliação de resultados. + ## 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/python.md b/i18n/pt-BR/docusaurus-plugin-content-docs/current/polyglot/python.md index 1ce414de524..cb546ed266b 100644 --- a/i18n/pt-BR/docusaurus-plugin-content-docs/current/polyglot/python.md +++ b/i18n/pt-BR/docusaurus-plugin-content-docs/current/polyglot/python.md @@ -1108,6 +1108,39 @@ async def long_running_task(items: list) -> dict: return {"processed": len(items)} ``` +#### Identidade da execução lógica de uma atividade {#activity-identity} + +Python SDK 2.15.0 e posteriores expõem o campo opcional somente leitura +`activity.context().info.activity_execution_id`. Ele identifica uma execução +lógica de atividade entre tentativas. `info.workflow_id` e `info.run_id` +identificam a instância de workflow e a execução às quais ela pertence. +Use o ID da execução lógica como chave de idempotência do serviço externo. +Os IDs de tarefa e tentativa mudam ao tentar novamente e não devem substituí-lo. + +IDs de execução ausentes, inválidos ou em branco continuam sendo `None`, +inclusive em claims antigos. Strings recebidas que não estão em branco +preservam a grafia exata. Se uma operação exigir essa chave, recuse-a antes +do efeito externo quando o ID estiver indisponível. Atividades roteadas por +sessão usam a identidade de seu claim comum. Atividades locais preparadas +usam o ID de execução de seu recibo de admissão validado. Atividades locais +inline não têm ID de execução admitido e expõem `None`, mas preservam os +IDs do workflow e da execução pai. Mocks sem Server não criam identidade +de atividade do Server. + +Consulte o exemplo de modo serviço no [guia do SDK sobre o helper de chave de idempotência e a identidade de atividade](https://python.durable-workflow.com/sdk-reference/#activity-execution-identity). +Atribua sufixos de operação estáveis a operações externas diferentes e +garanta que o serviço de destino respeite a chave. Um ID de execução é +metadado público, não prova de um claim ativo nem autorização para um efeito +externo. Mantenha credenciais, fencing da tentativa atual e reconciliação de +resultados. O [recibo de nova tentativa comum com o pacote publicado](https://github.com/durable-workflow/.github/issues/211#issuecomment-6869562527) +vincula Python SDK 2.17.2 ao Server nativo 3.9.2. Ele comprova que os IDs de +execução lógica de atividade, instância de workflow e execução do workflow +permanecem estáveis, enquanto os IDs de tarefa e tentativa são distintos entre +as tentativas 1 e 2. Os comportamentos local e +de sessão mantêm seu escopo definido separadamente. Veja as +[garantias de execução](../constraints/execution-guarantees.md#service-activity-identity) +para o contrato compartilhado de idempotência. + #### Política de tentativas recebida e tentativa original {#activity-retry-metadata} Requer Python SDK **2.12.0 ou posterior**. `info = activity.context().info` diff --git a/i18n/pt-BR/source-hashes.json b/i18n/pt-BR/source-hashes.json index 094463e2c6f..045eb71aa6f 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": "c24aaff70bfcf50366459ec698ced67adff1e02c1b0ca23c8178a13873037f5a", + "constraints/execution-guarantees.md": "9e53840c400b14186587714b32dd54dd780aaa68f2a132fc1e4e4d1f3eeadd0b", "constraints/idempotent-vs-deterministic.md": "f7396f01a4111ce187e751b009c1efb96f5538e8a602006eed24f7b1d8f44adf", "constraints/overview.md": "fd6c842c6c22d6f0df37a52de15ca74b34664f5ecd78af0c08b1e0cdb9a2be1f", "constraints/structural-limits.md": "5c7b7f6c86c5ca547eb3f200400ceab3b589f32d83866914f44e3a5a7d81e964", @@ -84,7 +84,7 @@ "polyglot/polling-patterns.md": "30875099a23731c6c471b481a771378acc6ff57eed2fda4405a509057534c989", "polyglot/portable-worker-affinity.md": "40973c6a31a76845b4f95e9a505e68ad76abd5174bbdccf37993cdebc8904959", "polyglot/prerelease-history-migration.md": "a57f05f492228a8a67791f9152648a1e5f80856325b78777cf63b6ef49b7413c", - "polyglot/python.md": "82da06617fe24e70c5c89197d192a81430a282b788ef93afd3b3bcb690ba2a9f", + "polyglot/python.md": "57734052d6ffae8d660083626bf47fb7c392c492ab0581a8942401046bb25d38", "polyglot/runtime-migration.md": "5a78713bb8cb74aea58f6d5d826400d968a405f69c6ff17fdf2f7decb1d14b71", "polyglot/rust-cloud-quickstart.md": "2303434fc9302a81a8381ad4836423ef9952eb3201a4574c432254e3cb68c5f3", "polyglot/rust.md": "31950634b8ccdb5c288ba871cc7f816de6683c52bf738bfdc13fa7aa825c6335", 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 b51d48bb04e..9c19440827d 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 @@ -141,6 +141,20 @@ final class ChargeCard extends Activity Для 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 або сталого журналу ефектів; ці методи не надають відновлюваних контрольних точок. +Activity Python у сервісному режимі надають необов’язкове поле лише для +читання `activity.context().info.activity_execution_id`, а також `workflow_id` +і `run_id` для свого екземпляра workflow та запуску. Використовуйте ID +логічного виконання між повторними спробами. Відсутня ідентичність залишається +`None`. Ніколи не підставляйте замість неї ID задачі, спроби або сесії. +[Посібник з ідентичності Python](../polyglot/python.md#activity-identity) +посилається на приклад сервісного режиму, який підтримує SDK, і визначає +поведінку старих claims, сесій, підготовлених локальних activity, локальних +activity inline та контекстів без Server. Його квитанція з опублікованим +пакетом і нативним Server доводить лише ідентичність звичайних повторних +спроб. ID є публічними метаданими, а не повноваженнями claim, і не гарантує +зовнішній ефект рівно один раз. Зберігайте ідемпотентність зовнішнього +сервісу, різні ключі для різних ефектів та узгодження результатів. + ## Що розробники мають зробити ідемпотентним {#what-developers-must-make-idempotent} Вам **не** потрібно робити саме відтворення workflow ідемпотентним. Фреймворк diff --git a/i18n/uk/docusaurus-plugin-content-docs/current/polyglot/python.md b/i18n/uk/docusaurus-plugin-content-docs/current/polyglot/python.md index 5e14b1b62f8..dd61b1ff583 100644 --- a/i18n/uk/docusaurus-plugin-content-docs/current/polyglot/python.md +++ b/i18n/uk/docusaurus-plugin-content-docs/current/polyglot/python.md @@ -1092,6 +1092,37 @@ async def long_running_task(items: list) -> dict: return {"processed": len(items)} ``` +#### Ідентичність логічного виконання activity {#activity-identity} + +Python SDK 2.15.0 і новіші версії надають необов’язкове поле лише для читання +`activity.context().info.activity_execution_id`. Воно ідентифікує одне +логічне виконання activity між повторними спробами. `info.workflow_id` +та `info.run_id` ідентифікують його екземпляр workflow і запуск. Використовуйте +ID логічного виконання як ключ ідемпотентності зовнішнього сервісу. ID задачі +та спроби змінюються під час повторної спроби й не можуть його замінювати. + +Відсутні, некоректні або порожні ID виконання залишаються `None`, зокрема +в старих claims. Отримані рядки, що містять непробільні символи, зберігаються +точно. Якщо операція потребує цього ключа, відмовтеся від неї до зовнішнього +ефекту, коли ID недоступний. Activity, спрямовані до сесії, використовують +ідентичність свого звичайного claim. Підготовлені локальні activity +використовують ID виконання зі своєї перевіреної квитанції допуску. Локальні +activity inline не мають допущеного ID виконання й надають `None`, але +зберігають ID батьківського workflow та запуску. Моки без Server не створюють +ідентичності activity Server. + +Приклад для сервісного режиму наведено в [посібнику SDK із допоміжною функцією ключа ідемпотентності та ідентичності activity](https://python.durable-workflow.com/sdk-reference/#activity-execution-identity). +Додавайте різним зовнішнім операціям сталі суфікси операцій і переконайтеся, +що зовнішній сервіс враховує ключ. ID виконання є публічними метаданими, +а не доказом активного claim чи дозволом на зовнішній ефект. Зберігайте +облікові дані, fencing поточної спроби та узгодження результатів. +[Квитанція звичайної повторної спроби з опублікованим пакетом](https://github.com/durable-workflow/.github/issues/211#issuecomment-6869562527) +пов’язує Python SDK 2.17.2 із нативним Server 3.9.2. Вона доводить сталість +ідентичності логічного виконання, workflow та запуску і різні ID задачі та +спроби між спробами 1 і 2. Локальна й сесійна поведінка зберігають окремо +визначені межі. Спільний контракт ідемпотентності див. у +[гарантіях виконання](../constraints/execution-guarantees.md#service-activity-identity). + #### Отримана retry policy та початкова спроба {#activity-retry-metadata} Потрібен Python SDK **2.12.0 або новіший**. `info = activity.context().info` diff --git a/i18n/uk/source-hashes.json b/i18n/uk/source-hashes.json index 094463e2c6f..045eb71aa6f 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": "c24aaff70bfcf50366459ec698ced67adff1e02c1b0ca23c8178a13873037f5a", + "constraints/execution-guarantees.md": "9e53840c400b14186587714b32dd54dd780aaa68f2a132fc1e4e4d1f3eeadd0b", "constraints/idempotent-vs-deterministic.md": "f7396f01a4111ce187e751b009c1efb96f5538e8a602006eed24f7b1d8f44adf", "constraints/overview.md": "fd6c842c6c22d6f0df37a52de15ca74b34664f5ecd78af0c08b1e0cdb9a2be1f", "constraints/structural-limits.md": "5c7b7f6c86c5ca547eb3f200400ceab3b589f32d83866914f44e3a5a7d81e964", @@ -84,7 +84,7 @@ "polyglot/polling-patterns.md": "30875099a23731c6c471b481a771378acc6ff57eed2fda4405a509057534c989", "polyglot/portable-worker-affinity.md": "40973c6a31a76845b4f95e9a505e68ad76abd5174bbdccf37993cdebc8904959", "polyglot/prerelease-history-migration.md": "a57f05f492228a8a67791f9152648a1e5f80856325b78777cf63b6ef49b7413c", - "polyglot/python.md": "82da06617fe24e70c5c89197d192a81430a282b788ef93afd3b3bcb690ba2a9f", + "polyglot/python.md": "57734052d6ffae8d660083626bf47fb7c392c492ab0581a8942401046bb25d38", "polyglot/runtime-migration.md": "5a78713bb8cb74aea58f6d5d826400d968a405f69c6ff17fdf2f7decb1d14b71", "polyglot/rust-cloud-quickstart.md": "2303434fc9302a81a8381ad4836423ef9952eb3201a4574c432254e3cb68c5f3", "polyglot/rust.md": "31950634b8ccdb5c288ba871cc7f816de6683c52bf738bfdc13fa7aa825c6335", 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 554b32a9a28..714de1dd260 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 @@ -114,6 +114,15 @@ final class ChargeCard extends Activity 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 或持久化副作用账本;这些方法不提供可恢复检查点。 +Python 服务模式活动提供只读的可选字段 +`activity.context().info.activity_execution_id`,以及所属工作流实例和运行的 `workflow_id` +和 `run_id`。请在重试之间使用逻辑执行 ID。身份缺失时仍为 `None`,绝不能替换为任务、 +尝试或会话 ID。[Python 身份指南](../polyglot/python.md#activity-identity)链接到 SDK +维护的服务模式示例,并定义旧 claim、会话、预备本地活动、内联本地活动及不使用 Server +时的行为。其中已发布包与原生 Server 的回执仅证明普通重试的身份。ID 是公开元数据, +不是 claim 权限,也不会使外部副作用恰好发生一次。请保留下游幂等性、不同副作用使用 +不同键,以及结果对账。 + ## 开发者需要保证哪些操作幂等 {#what-developers-must-make-idempotent} 你无需让工作流重放本身具有幂等性。框架通过已提交历史重建状态,负责处理重放。 diff --git a/i18n/zh-Hans/docusaurus-plugin-content-docs/current/polyglot/python.md b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/polyglot/python.md index 451f8b8845c..1e4d8f0cadd 100644 --- a/i18n/zh-Hans/docusaurus-plugin-content-docs/current/polyglot/python.md +++ b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/polyglot/python.md @@ -894,6 +894,27 @@ async def long_running_task(items: list) -> dict: return {"processed": len(items)} ``` +#### 活动的逻辑执行标识 {#activity-identity} + +Python SDK 2.15.0 及更高版本提供只读的可选字段 +`activity.context().info.activity_execution_id`。它标识跨重试的同一次逻辑活动执行。 +`info.workflow_id` 和 `info.run_id` 标识其所属的工作流实例和运行。请将逻辑执行 ID +用作外部服务的幂等键。任务 ID 和尝试 ID 会在重试时变化,不能用来替代它。 + +执行 ID 缺失、无效或只含空白时仍为 `None`,旧 claim 也是如此。收到的非空白字符串 +会保留原样。如果操作要求此键,但 ID 不可用,请在产生外部副作用之前拒绝操作。 +通过会话路由的活动使用其普通 claim 的身份。预备本地活动使用经过验证的接纳回执中的 +执行 ID。内联本地活动没有已接纳的执行 ID,因此提供 `None`,但保留父工作流和运行的 +ID。不使用 Server 的 mock 不会创建 Server 活动身份。 + +服务模式示例见 SDK 的[幂等键辅助函数和活动身份指南](https://python.durable-workflow.com/sdk-reference/#activity-execution-identity)。 +为不同的外部操作添加稳定的操作后缀,并确保下游服务遵守幂等键。执行 ID 是公开元数据, +既不能证明 claim 仍然有效,也不是产生外部副作用的授权。请保留凭据、当前尝试的 +fencing 和结果对账。[使用已发布包的普通重试回执](https://github.com/durable-workflow/.github/issues/211#issuecomment-6869562527) +将 Python SDK 2.17.2 与原生 Server 3.9.2 绑定。它证明尝试 1 和 2 的逻辑执行、工作流和 +运行身份保持不变,而任务 ID 和尝试 ID 不同。本地和会话行为仍具有单独定义的范围。 +共享幂等契约见[执行保证](../constraints/execution-guarantees.md#service-activity-identity)。 + #### 收到的重试策略与原始尝试次数 {#activity-retry-metadata} 需要 Python SDK **2.12.0 或更高版本**。`info = activity.context().info` diff --git a/i18n/zh-Hans/source-hashes.json b/i18n/zh-Hans/source-hashes.json index 094463e2c6f..045eb71aa6f 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": "c24aaff70bfcf50366459ec698ced67adff1e02c1b0ca23c8178a13873037f5a", + "constraints/execution-guarantees.md": "9e53840c400b14186587714b32dd54dd780aaa68f2a132fc1e4e4d1f3eeadd0b", "constraints/idempotent-vs-deterministic.md": "f7396f01a4111ce187e751b009c1efb96f5538e8a602006eed24f7b1d8f44adf", "constraints/overview.md": "fd6c842c6c22d6f0df37a52de15ca74b34664f5ecd78af0c08b1e0cdb9a2be1f", "constraints/structural-limits.md": "5c7b7f6c86c5ca547eb3f200400ceab3b589f32d83866914f44e3a5a7d81e964", @@ -84,7 +84,7 @@ "polyglot/polling-patterns.md": "30875099a23731c6c471b481a771378acc6ff57eed2fda4405a509057534c989", "polyglot/portable-worker-affinity.md": "40973c6a31a76845b4f95e9a505e68ad76abd5174bbdccf37993cdebc8904959", "polyglot/prerelease-history-migration.md": "a57f05f492228a8a67791f9152648a1e5f80856325b78777cf63b6ef49b7413c", - "polyglot/python.md": "82da06617fe24e70c5c89197d192a81430a282b788ef93afd3b3bcb690ba2a9f", + "polyglot/python.md": "57734052d6ffae8d660083626bf47fb7c392c492ab0581a8942401046bb25d38", "polyglot/runtime-migration.md": "5a78713bb8cb74aea58f6d5d826400d968a405f69c6ff17fdf2f7decb1d14b71", "polyglot/rust-cloud-quickstart.md": "2303434fc9302a81a8381ad4836423ef9952eb3201a4574c432254e3cb68c5f3", "polyglot/rust.md": "31950634b8ccdb5c288ba871cc7f816de6683c52bf738bfdc13fa7aa825c6335",