From 4f6db301998336c91d6483db58a98bf12208b57b Mon Sep 17 00:00:00 2001 From: Durable Workflow Date: Thu, 22 Oct 2026 23:14:09 +0000 Subject: [PATCH] Explain Python heartbeat helpers in every guide locale --- docs/features/heartbeats.md | 5 +++++ docs/polyglot/python.md | 16 ++++++++++++++++ .../current/features/heartbeats.md | 5 +++++ .../current/polyglot/python.md | 18 ++++++++++++++++++ i18n/de/source-hashes.json | 4 ++-- .../current/features/heartbeats.md | 5 +++++ .../current/polyglot/python.md | 19 +++++++++++++++++++ i18n/es/source-hashes.json | 4 ++-- .../current/features/heartbeats.md | 5 +++++ .../current/polyglot/python.md | 18 ++++++++++++++++++ i18n/fr/source-hashes.json | 4 ++-- .../current/features/heartbeats.md | 5 +++++ .../current/polyglot/python.md | 16 ++++++++++++++++ i18n/ja/source-hashes.json | 4 ++-- .../current/features/heartbeats.md | 5 +++++ .../current/polyglot/python.md | 18 ++++++++++++++++++ i18n/pt-BR/source-hashes.json | 4 ++-- .../current/features/heartbeats.md | 5 +++++ .../current/polyglot/python.md | 18 ++++++++++++++++++ i18n/uk/source-hashes.json | 4 ++-- .../current/features/heartbeats.md | 4 ++++ .../current/polyglot/python.md | 13 +++++++++++++ i18n/zh-Hans/source-hashes.json | 4 ++-- 23 files changed, 189 insertions(+), 14 deletions(-) diff --git a/docs/features/heartbeats.md b/docs/features/heartbeats.md index 9e6256676fa..3e9b26d8813 100644 --- a/docs/features/heartbeats.md +++ b/docs/features/heartbeats.md @@ -40,6 +40,11 @@ Inside the activity, `activityId()`, `attemptId()`, and `attemptCount()` expose Polyglot workers can heartbeat via the HTTP worker bridge without constructing the PHP activity class — see the [worker protocol](/docs/polyglot/worker-protocol) for the endpoints. +A single blocking call may need a separate heartbeat helper. This reports +liveness, not progress: give the call its own finite deadline and stop the +helper when the call finishes or loses authority. Python workers should follow +the [captured-context and cancellation recipe](../polyglot/python.md#heartbeat-helper-thread). + ## Cadence and receipts {#heartbeat-cadence-and-receipts} For a queued activity, the first heartbeat deadline starts when the runtime claims it, before task delivery and user code. A recorded heartbeat sets the next deadline to its runtime timestamp plus `heartbeatTimeout`. Sending the request or receiving its response does not start another full window. See [Heartbeat timeout](./timeouts.md#heartbeat-timeout). diff --git a/docs/polyglot/python.md b/docs/polyglot/python.md index 6ea9fa3e91b..f64c8abc72c 100644 --- a/docs/polyglot/python.md +++ b/docs/polyglot/python.md @@ -1101,6 +1101,22 @@ registration. Set timeouts on downstream I/O and use separately isolated worker processes for CPU-heavy work. See the SDK's [execution and shutdown reference](https://python.durable-workflow.com/reference/worker/). +### Heartbeating from a helper thread {#heartbeat-helper-thread} + +For one long blocking call, capture `ctx = activity.context()` inside the +synchronous activity and pass it to the helper. A new thread does not +automatically inherit the activity context. Use `ctx.heartbeat_sync(details)` +from the helper, never from the worker event loop. See the SDK's +[complete helper-thread recipe](https://python.durable-workflow.com/reference/activity/#heartbeats-during-one-blocking-call). + +Stop and join the helper when the call returns or raises. If a heartbeat raises +`ActivityCancelled` or `ActivityLeaseAuthorityLost`, signal cooperative +cancellation to the call and re-raise the original exception before returning +a result. A helper exception cannot forcibly interrupt a blocked library call. +Give that call its own finite deadline and cancellation mechanism, and bound +heartbeat request timeouts and retries. Helper heartbeats can otherwise keep +reporting liveness while the work is hung. + ## Worker The `Worker` registers with the server, polls for tasks, and dispatches them to your workflow and activity implementations. diff --git a/i18n/de/docusaurus-plugin-content-docs/current/features/heartbeats.md b/i18n/de/docusaurus-plugin-content-docs/current/features/heartbeats.md index f2406140ef9..7b8f55d5cc4 100644 --- a/i18n/de/docusaurus-plugin-content-docs/current/features/heartbeats.md +++ b/i18n/de/docusaurus-plugin-content-docs/current/features/heartbeats.md @@ -58,6 +58,11 @@ Polyglotte Worker können Heartbeats über die HTTP-Worker-Brücke senden, ohne die PHP-Aktivitätsklasse zu erzeugen. Die Endpunkte beschreibt das [Worker-Protokoll](/docs/polyglot/worker-protocol). +Ein einzelner blockierender Aufruf kann einen eigenen Heartbeat-Hilfsthread +benötigen. Dieser meldet Lebenszeichen, keinen Fortschritt. Setzen Sie dem +Aufruf eine eigene endliche Frist und beenden Sie den Hilfsthread bei Abschluss +oder Autoritätsverlust. Python-Worker sollten die [Anleitung für erfassten Kontext und Abbruch](../polyglot/python.md#heartbeat-helper-thread) befolgen. + ## Takt und Bestätigungen {#heartbeat-cadence-and-receipts} Bei einer Aktivität in der Warteschlange beginnt die erste Heartbeat-Frist, wenn die Laufzeit sie beansprucht, also vor der Aufgabenauslieferung und dem Anwendungscode. Ein aufgezeichneter Heartbeat setzt die nächste Frist auf seinen Laufzeitzeitpunkt plus `heartbeatTimeout`. Weder das Senden der Anfrage noch der Empfang ihrer Antwort eröffnet ein weiteres vollständiges Zeitfenster. Siehe [Heartbeat-Zeitlimit](./timeouts.md#heartbeat-timeout). 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 4f22edc99a5..9cf475595fe 100644 --- a/i18n/de/docusaurus-plugin-content-docs/current/polyglot/python.md +++ b/i18n/de/docusaurus-plugin-content-docs/current/polyglot/python.md @@ -1077,6 +1077,24 @@ Ein-/Ausgabe fest und verwenden Sie für rechenintensive Arbeit getrennte, isoli Worker-Prozesse. Siehe die [SDK-Referenz zu Ausführung und Herunterfahren](https://python.durable-workflow.com/reference/worker/). +### Heartbeats aus einem Hilfsthread {#heartbeat-helper-thread} + +Erfassen Sie bei einem langen blockierenden Aufruf `ctx = activity.context()` +innerhalb der synchronen Aktivität und übergeben Sie den Kontext an den +Hilfsthread. Ein neuer Thread erbt den Aktivitätskontext nicht automatisch. +Verwenden Sie dort `ctx.heartbeat_sync(details)`, niemals in der Ereignisschleife +des Workers. Die [vollständige Anleitung](https://python.durable-workflow.com/reference/activity/#heartbeats-during-one-blocking-call) +steht in der SDK-Referenz. + +Beenden Sie den Hilfsthread bei Rückkehr oder Fehler des Aufrufs und warten Sie +mit `join()` auf sein Ende. Löst ein Heartbeat `ActivityCancelled` oder +`ActivityLeaseAuthorityLost` aus, signalisieren Sie dem Aufruf den kooperativen +Abbruch und lösen Sie vor der Ergebnisrückgabe die ursprüngliche Ausnahme erneut +aus. Eine Ausnahme im Hilfsthread kann einen blockierten Bibliotheksaufruf nicht +gewaltsam unterbrechen. Geben Sie diesem eine eigene endliche Frist und einen +Abbruchmechanismus. Begrenzen Sie auch Heartbeat-Anfragen und Wiederholungen. +Andernfalls meldet der Hilfsthread weiter Lebenszeichen, obwohl die Arbeit hängt. + ## Worker {#worker} Der `Worker` registriert sich beim Server, fragt Tasks ab und übergibt sie an Ihre Workflow- und Aktivitätsimplementierungen. diff --git a/i18n/de/source-hashes.json b/i18n/de/source-hashes.json index d545f965ece..cd5934052fe 100644 --- a/i18n/de/source-hashes.json +++ b/i18n/de/source-hashes.json @@ -37,7 +37,7 @@ "features/continue-as-new.md": "6b3cc8f8c5375726ff0b2544da01e7206e964908b436544e284068ab67aa3dbb", "features/events.md": "fcb391862938b5e8cf44ad39f213fc3e55b2ecb7c6edebe6a83a1e58a60bf56e", "features/external-payload-storage.md": "acc312fa2f50a43c96e1d235439124d28a7048f0bf3abac34319467fcbf7e898", - "features/heartbeats.md": "38675bb919f56480baf62f6c6588ae168c62544a97d5a97c9486c1264ed7147c", + "features/heartbeats.md": "e3d84178788dff92954e08d08f006def0a991a481f99301facbda8c6ca21a7a0", "features/local-activities.md": "05fca8f2104d8f4e7bd8b48040f5615f18d0ee2795922fb65c56f8d3d70ed204", "features/memo.md": "621aa630e37fbef6f84d761c92f99dc3fe8756879008c659cbad0600eb14fd5d", "features/message-streams.md": "3bce915ed750793b31360d2accc94eebf2c7f075b9769e072f8a2d3d034afad0", @@ -82,7 +82,7 @@ "polyglot/polling-patterns.md": "30875099a23731c6c471b481a771378acc6ff57eed2fda4405a509057534c989", "polyglot/portable-worker-affinity.md": "40973c6a31a76845b4f95e9a505e68ad76abd5174bbdccf37993cdebc8904959", "polyglot/prerelease-history-migration.md": "a57f05f492228a8a67791f9152648a1e5f80856325b78777cf63b6ef49b7413c", - "polyglot/python.md": "9d6f4d4f0d01ec8d6d937892f3ab0f90d13755a93a7e902e821da8938dd2bacf", + "polyglot/python.md": "a9fc8330cbc78953244b94a170197038a299a5a25fa78c38c7bfb451fd67d345", "polyglot/rust-cloud-quickstart.md": "2303434fc9302a81a8381ad4836423ef9952eb3201a4574c432254e3cb68c5f3", "polyglot/rust.md": "32de05a771b5ee6d8cf54fdd408222372995ce29c8be63102abe58b977ac8ef0", "polyglot/server-api-reference.md": "e94af77a13b341d6fdc9941d4ee94e5053ab932d2e77069b238eb33351414e83", diff --git a/i18n/es/docusaurus-plugin-content-docs/current/features/heartbeats.md b/i18n/es/docusaurus-plugin-content-docs/current/features/heartbeats.md index 0d4c68ce504..7e6bb865971 100644 --- a/i18n/es/docusaurus-plugin-content-docs/current/features/heartbeats.md +++ b/i18n/es/docusaurus-plugin-content-docs/current/features/heartbeats.md @@ -40,6 +40,11 @@ Dentro de la actividad, `activityId()`, `attemptId()` y `attemptCount()` exponen Los workers políglotas pueden enviar latidos mediante el puente HTTP sin construir la clase PHP de actividad. Consulta los endpoints en el [protocolo de workers](/docs/polyglot/worker-protocol). +Una llamada bloqueante puede necesitar un auxiliar dedicado a enviar heartbeats. +Este indica que el proceso sigue vivo, no que avance. Pon un plazo finito a la +llamada y detén el auxiliar cuando termine o pierda la autoridad. En Python, +sigue la [receta de captura de contexto y cancelación](../polyglot/python.md#heartbeat-helper-thread). + ## Cadencia y confirmaciones {#heartbeat-cadence-and-receipts} Para una actividad encolada, el primer plazo de heartbeat empieza cuando el entorno de ejecución la reclama, antes de entregar la tarea y ejecutar código de usuario. Un heartbeat registrado fija el siguiente plazo en su marca de tiempo del entorno más `heartbeatTimeout`. Ni enviar la petición ni recibir su respuesta abre otra ventana completa. Consulte [Tiempo de espera de heartbeat](./timeouts.md#heartbeat-timeout). 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 fab47871f70..ea02ace512f 100644 --- a/i18n/es/docusaurus-plugin-content-docs/current/polyglot/python.md +++ b/i18n/es/docusaurus-plugin-content-docs/current/polyglot/python.md @@ -1053,6 +1053,25 @@ el registro del worker. Limite los tiempos de espera de E/S de los servicios invocados y use procesos de worker aislados para trabajo intensivo de CPU. Consulte la [referencia de ejecución y cierre del SDK](https://python.durable-workflow.com/reference/worker/). +### Heartbeats desde un hilo auxiliar {#heartbeat-helper-thread} + +Para una llamada larga y bloqueante, captura `ctx = activity.context()` dentro +de la actividad síncrona y pásalo al hilo auxiliar. Un hilo nuevo no hereda +automáticamente el contexto de actividad. Usa `ctx.heartbeat_sync(details)` +desde el auxiliar, nunca desde el bucle de eventos del worker. Consulta la +[receta completa](https://python.durable-workflow.com/reference/activity/#heartbeats-during-one-blocking-call) +en la referencia del SDK. + +Detén el auxiliar y espera su terminación con `join()` tanto si la llamada +devuelve un resultado como si falla. Si un heartbeat lanza `ActivityCancelled` +o `ActivityLeaseAuthorityLost`, solicita la cancelación cooperativa de la +llamada y vuelve a lanzar la excepción original antes de devolver un resultado. +Una excepción en el auxiliar no puede interrumpir por la fuerza una llamada +bloqueada. Dale un plazo finito y un mecanismo de cancelación propios, y limita +los tiempos de espera y reintentos de las peticiones de heartbeat. De lo +contrario, el auxiliar puede seguir indicando actividad mientras el trabajo +está colgado. + ## Worker {#worker} `Worker` se registra, sondea tareas y las despacha a tus implementaciones. diff --git a/i18n/es/source-hashes.json b/i18n/es/source-hashes.json index d545f965ece..cd5934052fe 100644 --- a/i18n/es/source-hashes.json +++ b/i18n/es/source-hashes.json @@ -37,7 +37,7 @@ "features/continue-as-new.md": "6b3cc8f8c5375726ff0b2544da01e7206e964908b436544e284068ab67aa3dbb", "features/events.md": "fcb391862938b5e8cf44ad39f213fc3e55b2ecb7c6edebe6a83a1e58a60bf56e", "features/external-payload-storage.md": "acc312fa2f50a43c96e1d235439124d28a7048f0bf3abac34319467fcbf7e898", - "features/heartbeats.md": "38675bb919f56480baf62f6c6588ae168c62544a97d5a97c9486c1264ed7147c", + "features/heartbeats.md": "e3d84178788dff92954e08d08f006def0a991a481f99301facbda8c6ca21a7a0", "features/local-activities.md": "05fca8f2104d8f4e7bd8b48040f5615f18d0ee2795922fb65c56f8d3d70ed204", "features/memo.md": "621aa630e37fbef6f84d761c92f99dc3fe8756879008c659cbad0600eb14fd5d", "features/message-streams.md": "3bce915ed750793b31360d2accc94eebf2c7f075b9769e072f8a2d3d034afad0", @@ -82,7 +82,7 @@ "polyglot/polling-patterns.md": "30875099a23731c6c471b481a771378acc6ff57eed2fda4405a509057534c989", "polyglot/portable-worker-affinity.md": "40973c6a31a76845b4f95e9a505e68ad76abd5174bbdccf37993cdebc8904959", "polyglot/prerelease-history-migration.md": "a57f05f492228a8a67791f9152648a1e5f80856325b78777cf63b6ef49b7413c", - "polyglot/python.md": "9d6f4d4f0d01ec8d6d937892f3ab0f90d13755a93a7e902e821da8938dd2bacf", + "polyglot/python.md": "a9fc8330cbc78953244b94a170197038a299a5a25fa78c38c7bfb451fd67d345", "polyglot/rust-cloud-quickstart.md": "2303434fc9302a81a8381ad4836423ef9952eb3201a4574c432254e3cb68c5f3", "polyglot/rust.md": "32de05a771b5ee6d8cf54fdd408222372995ce29c8be63102abe58b977ac8ef0", "polyglot/server-api-reference.md": "e94af77a13b341d6fdc9941d4ee94e5053ab932d2e77069b238eb33351414e83", diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/features/heartbeats.md b/i18n/fr/docusaurus-plugin-content-docs/current/features/heartbeats.md index 9a3106e5b38..f90c306c7e9 100644 --- a/i18n/fr/docusaurus-plugin-content-docs/current/features/heartbeats.md +++ b/i18n/fr/docusaurus-plugin-content-docs/current/features/heartbeats.md @@ -40,6 +40,11 @@ Dans l’activité, `activityId()`, `attemptId()` et `attemptCount()` exposent l Les workers polyglottes peuvent envoyer des battements via la passerelle HTTP des workers sans instancier la classe PHP d’activité. Consultez le [protocole des workers](/docs/polyglot/worker-protocol) pour les points de terminaison. +Un appel bloquant peut nécessiter un auxiliaire dédié aux heartbeats. Celui-ci +signale que le processus vit, pas que le travail avance. Donnez à l’appel son +propre délai fini et arrêtez l’auxiliaire à la fin ou à la perte d’autorité. +Pour Python, suivez l’[exemple de capture du contexte et d’annulation](../polyglot/python.md#heartbeat-helper-thread). + ## Fréquence et confirmations {#heartbeat-cadence-and-receipts} Pour une activité mise en file d’attente, la première échéance de heartbeat commence lorsque le moteur la réclame, avant la livraison de la tâche et le code applicatif. Un heartbeat enregistré fixe la prochaine échéance à son horodatage du moteur plus `heartbeatTimeout`. Ni l’envoi de la requête ni la réception de sa réponse n’ouvre une nouvelle fenêtre complète. Consultez [Délai de heartbeat](./timeouts.md#heartbeat-timeout). 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 8a82040f3fa..20a4a8df3ae 100644 --- a/i18n/fr/docusaurus-plugin-content-docs/current/polyglot/python.md +++ b/i18n/fr/docusaurus-plugin-content-docs/current/polyglot/python.md @@ -1077,6 +1077,24 @@ l’enregistrement du worker. Fixez des délais pour les E/S vers les services a et utilisez des processus de worker isolés pour les calculs intensifs. Consultez la [référence du SDK sur l’exécution et l’arrêt](https://python.durable-workflow.com/reference/worker/). +### Heartbeats depuis un thread auxiliaire {#heartbeat-helper-thread} + +Pour un long appel bloquant, capturez `ctx = activity.context()` dans +l’activité synchrone, puis transmettez ce contexte au thread auxiliaire. Un +nouveau thread n’hérite pas automatiquement du contexte d’activité. Appelez +`ctx.heartbeat_sync(details)` depuis ce thread, jamais depuis la boucle +événementielle du worker. Consultez l’[exemple complet](https://python.durable-workflow.com/reference/activity/#heartbeats-during-one-blocking-call) +dans la référence du SDK. + +Arrêtez le thread et attendez sa fin avec `join()` quand l’appel retourne ou +lève une exception. Si un heartbeat lève `ActivityCancelled` ou +`ActivityLeaseAuthorityLost`, signalez l’annulation coopérative à l’appel et +relancez l’exception d’origine avant de retourner un résultat. Une exception +dans le thread auxiliaire ne peut pas interrompre de force un appel bloqué. +Prévoyez un délai fini et un mécanisme d’annulation pour cet appel, et bornez +les délais et tentatives des requêtes de heartbeat. Sinon, le thread peut +continuer à signaler que le processus vit alors que le travail est bloqué. + ## Worker {#worker} `Worker` s'enregistre auprès du serveur, interroge les tâches et les transmet diff --git a/i18n/fr/source-hashes.json b/i18n/fr/source-hashes.json index d545f965ece..cd5934052fe 100644 --- a/i18n/fr/source-hashes.json +++ b/i18n/fr/source-hashes.json @@ -37,7 +37,7 @@ "features/continue-as-new.md": "6b3cc8f8c5375726ff0b2544da01e7206e964908b436544e284068ab67aa3dbb", "features/events.md": "fcb391862938b5e8cf44ad39f213fc3e55b2ecb7c6edebe6a83a1e58a60bf56e", "features/external-payload-storage.md": "acc312fa2f50a43c96e1d235439124d28a7048f0bf3abac34319467fcbf7e898", - "features/heartbeats.md": "38675bb919f56480baf62f6c6588ae168c62544a97d5a97c9486c1264ed7147c", + "features/heartbeats.md": "e3d84178788dff92954e08d08f006def0a991a481f99301facbda8c6ca21a7a0", "features/local-activities.md": "05fca8f2104d8f4e7bd8b48040f5615f18d0ee2795922fb65c56f8d3d70ed204", "features/memo.md": "621aa630e37fbef6f84d761c92f99dc3fe8756879008c659cbad0600eb14fd5d", "features/message-streams.md": "3bce915ed750793b31360d2accc94eebf2c7f075b9769e072f8a2d3d034afad0", @@ -82,7 +82,7 @@ "polyglot/polling-patterns.md": "30875099a23731c6c471b481a771378acc6ff57eed2fda4405a509057534c989", "polyglot/portable-worker-affinity.md": "40973c6a31a76845b4f95e9a505e68ad76abd5174bbdccf37993cdebc8904959", "polyglot/prerelease-history-migration.md": "a57f05f492228a8a67791f9152648a1e5f80856325b78777cf63b6ef49b7413c", - "polyglot/python.md": "9d6f4d4f0d01ec8d6d937892f3ab0f90d13755a93a7e902e821da8938dd2bacf", + "polyglot/python.md": "a9fc8330cbc78953244b94a170197038a299a5a25fa78c38c7bfb451fd67d345", "polyglot/rust-cloud-quickstart.md": "2303434fc9302a81a8381ad4836423ef9952eb3201a4574c432254e3cb68c5f3", "polyglot/rust.md": "32de05a771b5ee6d8cf54fdd408222372995ce29c8be63102abe58b977ac8ef0", "polyglot/server-api-reference.md": "e94af77a13b341d6fdc9941d4ee94e5053ab932d2e77069b238eb33351414e83", diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/features/heartbeats.md b/i18n/ja/docusaurus-plugin-content-docs/current/features/heartbeats.md index 1a59da010ac..1d1c0250c3c 100644 --- a/i18n/ja/docusaurus-plugin-content-docs/current/features/heartbeats.md +++ b/i18n/ja/docusaurus-plugin-content-docs/current/features/heartbeats.md @@ -40,6 +40,11 @@ final class PollRemoteJob extends Activity 多言語 Worker は PHP のアクティビティクラスを構築せずに HTTP Worker ブリッジでハートビートを送信できます。エンドポイントは [Worker プロトコル](/docs/polyglot/worker-protocol)を参照してください。 +単一のブロッキング呼び出しには、ハートビート用の補助処理が必要な場合があります。 +これは進捗ではなく生存の通知です。呼び出し自体に有限の期限を設定し、 +完了時や実行権限を失った時は補助処理を停止してください。 +Python では[コンテキストの取得とキャンセルの実装例](../polyglot/python.md#heartbeat-helper-thread)に従ってください。 + ## 送信間隔と確認 {#heartbeat-cadence-and-receipts} キューに入ったアクティビティでは、最初のハートビート期限はランタイムの取得時点から始まり、タスクの配信やユーザーコードの実行より前です。記録されたハートビートは、ランタイムの時刻に `heartbeatTimeout` を加えて次の期限を設定します。リクエストの送信時や応答の受信時に、期間が最初から始まるわけではありません。[ハートビートのタイムアウト](./timeouts.md#heartbeat-timeout)を参照してください。 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 64dc8e8d835..19fbe1c6a73 100644 --- a/i18n/ja/docusaurus-plugin-content-docs/current/polyglot/python.md +++ b/i18n/ja/docusaurus-plugin-content-docs/current/polyglot/python.md @@ -890,6 +890,22 @@ async def validate(data: dict) -> dict: 呼び出し先の I/O タイムアウトを制限し、CPU 負荷の高い処理には個別に分離したワーカープロセスを使ってください。 詳しくは [SDK の実行とシャットダウンのリファレンス](https://python.durable-workflow.com/reference/worker/)を参照してください。 +### 補助スレッドからのハートビート {#heartbeat-helper-thread} + +長時間のブロッキング呼び出しでは、同期アクティビティ内で +`ctx = activity.context()` を取得し、補助スレッドに渡してください。 +新しいスレッドにはアクティビティのコンテキストが自動では引き継がれません。 +補助スレッドでは `ctx.heartbeat_sync(details)` を使い、ワーカーのイベントループ上では +呼び出さないでください。SDK リファレンスの[完全な実装例](https://python.durable-workflow.com/reference/activity/#heartbeats-during-one-blocking-call)を参照してください。 + +呼び出しが正常終了した場合も例外を送出した場合も、補助スレッドを停止して +`join()` で終了を待ちます。ハートビートが `ActivityCancelled` または +`ActivityLeaseAuthorityLost` を送出したら、呼び出しに協調的なキャンセルを通知し、 +結果を返す前に元の例外を再送出してください。補助スレッドの例外では、 +ブロック中のライブラリ呼び出しを強制的に中断できません。呼び出し自体に有限の期限と +キャンセル手段を設け、ハートビート要求のタイムアウトと再試行も制限してください。 +そうしないと、処理が停止していても補助スレッドが生存を通知し続けます。 + ## Worker {#worker} `Worker` は Server に登録し、タスクをポーリングして、ワークフローとアクティビティの実装へディスパッチします。 diff --git a/i18n/ja/source-hashes.json b/i18n/ja/source-hashes.json index d545f965ece..cd5934052fe 100644 --- a/i18n/ja/source-hashes.json +++ b/i18n/ja/source-hashes.json @@ -37,7 +37,7 @@ "features/continue-as-new.md": "6b3cc8f8c5375726ff0b2544da01e7206e964908b436544e284068ab67aa3dbb", "features/events.md": "fcb391862938b5e8cf44ad39f213fc3e55b2ecb7c6edebe6a83a1e58a60bf56e", "features/external-payload-storage.md": "acc312fa2f50a43c96e1d235439124d28a7048f0bf3abac34319467fcbf7e898", - "features/heartbeats.md": "38675bb919f56480baf62f6c6588ae168c62544a97d5a97c9486c1264ed7147c", + "features/heartbeats.md": "e3d84178788dff92954e08d08f006def0a991a481f99301facbda8c6ca21a7a0", "features/local-activities.md": "05fca8f2104d8f4e7bd8b48040f5615f18d0ee2795922fb65c56f8d3d70ed204", "features/memo.md": "621aa630e37fbef6f84d761c92f99dc3fe8756879008c659cbad0600eb14fd5d", "features/message-streams.md": "3bce915ed750793b31360d2accc94eebf2c7f075b9769e072f8a2d3d034afad0", @@ -82,7 +82,7 @@ "polyglot/polling-patterns.md": "30875099a23731c6c471b481a771378acc6ff57eed2fda4405a509057534c989", "polyglot/portable-worker-affinity.md": "40973c6a31a76845b4f95e9a505e68ad76abd5174bbdccf37993cdebc8904959", "polyglot/prerelease-history-migration.md": "a57f05f492228a8a67791f9152648a1e5f80856325b78777cf63b6ef49b7413c", - "polyglot/python.md": "9d6f4d4f0d01ec8d6d937892f3ab0f90d13755a93a7e902e821da8938dd2bacf", + "polyglot/python.md": "a9fc8330cbc78953244b94a170197038a299a5a25fa78c38c7bfb451fd67d345", "polyglot/rust-cloud-quickstart.md": "2303434fc9302a81a8381ad4836423ef9952eb3201a4574c432254e3cb68c5f3", "polyglot/rust.md": "32de05a771b5ee6d8cf54fdd408222372995ce29c8be63102abe58b977ac8ef0", "polyglot/server-api-reference.md": "e94af77a13b341d6fdc9941d4ee94e5053ab932d2e77069b238eb33351414e83", diff --git a/i18n/pt-BR/docusaurus-plugin-content-docs/current/features/heartbeats.md b/i18n/pt-BR/docusaurus-plugin-content-docs/current/features/heartbeats.md index f9f5eda689c..51d0fea8eab 100644 --- a/i18n/pt-BR/docusaurus-plugin-content-docs/current/features/heartbeats.md +++ b/i18n/pt-BR/docusaurus-plugin-content-docs/current/features/heartbeats.md @@ -40,6 +40,11 @@ Dentro da atividade, `activityId()`, `attemptId()` e `attemptCount()` expõem a Workers poliglotas podem enviar heartbeats pela ponte HTTP de workers sem instanciar a classe de atividade PHP. Consulte os endpoints no [protocolo de workers](/docs/polyglot/worker-protocol). +Uma chamada bloqueante pode precisar de uma auxiliar dedicada a heartbeats. +Ela indica que o processo está vivo, não que está progredindo. Dê à chamada +um prazo finito próprio e pare a auxiliar quando ela terminar ou perder a +autoridade. No Python, siga o [exemplo de captura do contexto e cancelamento](../polyglot/python.md#heartbeat-helper-thread). + ## Cadência e confirmações {#heartbeat-cadence-and-receipts} Para uma atividade em fila, o primeiro prazo de heartbeat começa quando o runtime a reivindica, antes da entrega da tarefa e da execução do código do usuário. Um heartbeat registrado define o próximo prazo como seu horário no runtime mais `heartbeatTimeout`. Enviar a requisição ou receber sua resposta não inicia outra janela completa. Consulte [Tempo limite de heartbeat](./timeouts.md#heartbeat-timeout). 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 caee0afaabd..d2d6fa30630 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 @@ -1076,6 +1076,24 @@ registro do worker. Limite os tempos de espera de E/S dos serviços chamados e use processos de worker isolados para trabalho intensivo de CPU. Consulte a [referência de execução e encerramento do SDK](https://python.durable-workflow.com/reference/worker/). +### Heartbeats em uma thread auxiliar {#heartbeat-helper-thread} + +Para uma chamada longa e bloqueante, capture `ctx = activity.context()` dentro +da atividade síncrona e passe esse contexto à thread auxiliar. Uma nova thread +não herda automaticamente o contexto da atividade. Chame +`ctx.heartbeat_sync(details)` na auxiliar, nunca no loop de eventos do worker. +Veja o [exemplo completo](https://python.durable-workflow.com/reference/activity/#heartbeats-during-one-blocking-call) +na referência do SDK. + +Pare a auxiliar e aguarde seu término com `join()` quando a chamada retornar +ou lançar uma exceção. Se um heartbeat lançar `ActivityCancelled` ou +`ActivityLeaseAuthorityLost`, sinalize o cancelamento cooperativo à chamada e +relance a exceção original antes de retornar um resultado. Uma exceção na +auxiliar não interrompe à força uma chamada bloqueada. Defina um prazo finito +e um mecanismo de cancelamento para a chamada e limite os tempos e as +tentativas das requisições de heartbeat. Caso contrário, a auxiliar pode +continuar indicando atividade enquanto o trabalho está travado. + ## Worker {#worker} O `Worker` se registra no servidor, faz poll por tarefas e as despacha para diff --git a/i18n/pt-BR/source-hashes.json b/i18n/pt-BR/source-hashes.json index d545f965ece..cd5934052fe 100644 --- a/i18n/pt-BR/source-hashes.json +++ b/i18n/pt-BR/source-hashes.json @@ -37,7 +37,7 @@ "features/continue-as-new.md": "6b3cc8f8c5375726ff0b2544da01e7206e964908b436544e284068ab67aa3dbb", "features/events.md": "fcb391862938b5e8cf44ad39f213fc3e55b2ecb7c6edebe6a83a1e58a60bf56e", "features/external-payload-storage.md": "acc312fa2f50a43c96e1d235439124d28a7048f0bf3abac34319467fcbf7e898", - "features/heartbeats.md": "38675bb919f56480baf62f6c6588ae168c62544a97d5a97c9486c1264ed7147c", + "features/heartbeats.md": "e3d84178788dff92954e08d08f006def0a991a481f99301facbda8c6ca21a7a0", "features/local-activities.md": "05fca8f2104d8f4e7bd8b48040f5615f18d0ee2795922fb65c56f8d3d70ed204", "features/memo.md": "621aa630e37fbef6f84d761c92f99dc3fe8756879008c659cbad0600eb14fd5d", "features/message-streams.md": "3bce915ed750793b31360d2accc94eebf2c7f075b9769e072f8a2d3d034afad0", @@ -82,7 +82,7 @@ "polyglot/polling-patterns.md": "30875099a23731c6c471b481a771378acc6ff57eed2fda4405a509057534c989", "polyglot/portable-worker-affinity.md": "40973c6a31a76845b4f95e9a505e68ad76abd5174bbdccf37993cdebc8904959", "polyglot/prerelease-history-migration.md": "a57f05f492228a8a67791f9152648a1e5f80856325b78777cf63b6ef49b7413c", - "polyglot/python.md": "9d6f4d4f0d01ec8d6d937892f3ab0f90d13755a93a7e902e821da8938dd2bacf", + "polyglot/python.md": "a9fc8330cbc78953244b94a170197038a299a5a25fa78c38c7bfb451fd67d345", "polyglot/rust-cloud-quickstart.md": "2303434fc9302a81a8381ad4836423ef9952eb3201a4574c432254e3cb68c5f3", "polyglot/rust.md": "32de05a771b5ee6d8cf54fdd408222372995ce29c8be63102abe58b977ac8ef0", "polyglot/server-api-reference.md": "e94af77a13b341d6fdc9941d4ee94e5053ab932d2e77069b238eb33351414e83", diff --git a/i18n/uk/docusaurus-plugin-content-docs/current/features/heartbeats.md b/i18n/uk/docusaurus-plugin-content-docs/current/features/heartbeats.md index 6a1fbf9172b..07257f5f991 100644 --- a/i18n/uk/docusaurus-plugin-content-docs/current/features/heartbeats.md +++ b/i18n/uk/docusaurus-plugin-content-docs/current/features/heartbeats.md @@ -40,6 +40,11 @@ final class PollRemoteJob extends Activity Worker різних мов можуть надсилати heartbeat через HTTP-міст worker без створення екземпляра PHP-класу activity. Кінцеві точки наведено в [протоколі worker](/docs/polyglot/worker-protocol). +Окремий блокувальний виклик може потребувати допоміжного потоку для heartbeat. +Це підтверджує життєздатність, а не прогрес. Задайте виклику власний скінченний +термін і зупиніть допоміжний потік після завершення або втрати повноважень. +У Python дотримуйтеся [прикладу зі збереженням контексту та скасуванням](../polyglot/python.md#heartbeat-helper-thread). + ## Періодичність і підтвердження {#heartbeat-cadence-and-receipts} Для activity у черзі перший кінцевий термін heartbeat починається, коли runtime отримує її завдання, ще до доставлення завдання та користувацького коду. Записаний heartbeat встановлює наступний термін як свій час у runtime плюс `heartbeatTimeout`. Надсилання запиту чи отримання відповіді не починає нового повного вікна. Див. [Тайм-аут heartbeat](./timeouts.md#heartbeat-timeout). 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 7b843e25cf4..2df4e3ad415 100644 --- a/i18n/uk/docusaurus-plugin-content-docs/current/polyglot/python.md +++ b/i18n/uk/docusaurus-plugin-content-docs/current/polyglot/python.md @@ -1061,6 +1061,24 @@ async def validate(data: dict) -> dict: використовуйте окремі ізольовані процеси воркерів для обчислень, що інтенсивно навантажують CPU. Див. [довідник SDK щодо виконання та завершення роботи](https://python.durable-workflow.com/reference/worker/). +### Heartbeat із допоміжного потоку {#heartbeat-helper-thread} + +Для тривалого блокувального виклику отримайте `ctx = activity.context()` +усередині синхронної активності й передайте цей контекст допоміжному потоку. +Новий потік не успадковує контекст активності автоматично. Викликайте +`ctx.heartbeat_sync(details)` із допоміжного потоку, ніколи з циклу подій +воркера. Повний [приклад](https://python.durable-workflow.com/reference/activity/#heartbeats-during-one-blocking-call) +наведено в довіднику SDK. + +Зупиняйте допоміжний потік і чекайте його завершення через `join()`, коли +виклик повертає результат або піднімає виняток. Якщо heartbeat піднімає +`ActivityCancelled` чи `ActivityLeaseAuthorityLost`, подайте виклику сигнал +кооперативного скасування та повторно підніміть початковий виняток до повернення +результату. Виняток у допоміжному потоці не може примусово перервати блокувальний +виклик. Задайте йому власний скінченний термін і механізм скасування, а також +обмежте таймаути й повтори heartbeat-запитів. Інакше потік може надалі повідомляти +про життєздатність процесу, хоча робота зависла. + ## Worker {#worker} `Worker` реєструється на Server, опитує завдання й направляє їх до ваших diff --git a/i18n/uk/source-hashes.json b/i18n/uk/source-hashes.json index d545f965ece..cd5934052fe 100644 --- a/i18n/uk/source-hashes.json +++ b/i18n/uk/source-hashes.json @@ -37,7 +37,7 @@ "features/continue-as-new.md": "6b3cc8f8c5375726ff0b2544da01e7206e964908b436544e284068ab67aa3dbb", "features/events.md": "fcb391862938b5e8cf44ad39f213fc3e55b2ecb7c6edebe6a83a1e58a60bf56e", "features/external-payload-storage.md": "acc312fa2f50a43c96e1d235439124d28a7048f0bf3abac34319467fcbf7e898", - "features/heartbeats.md": "38675bb919f56480baf62f6c6588ae168c62544a97d5a97c9486c1264ed7147c", + "features/heartbeats.md": "e3d84178788dff92954e08d08f006def0a991a481f99301facbda8c6ca21a7a0", "features/local-activities.md": "05fca8f2104d8f4e7bd8b48040f5615f18d0ee2795922fb65c56f8d3d70ed204", "features/memo.md": "621aa630e37fbef6f84d761c92f99dc3fe8756879008c659cbad0600eb14fd5d", "features/message-streams.md": "3bce915ed750793b31360d2accc94eebf2c7f075b9769e072f8a2d3d034afad0", @@ -82,7 +82,7 @@ "polyglot/polling-patterns.md": "30875099a23731c6c471b481a771378acc6ff57eed2fda4405a509057534c989", "polyglot/portable-worker-affinity.md": "40973c6a31a76845b4f95e9a505e68ad76abd5174bbdccf37993cdebc8904959", "polyglot/prerelease-history-migration.md": "a57f05f492228a8a67791f9152648a1e5f80856325b78777cf63b6ef49b7413c", - "polyglot/python.md": "9d6f4d4f0d01ec8d6d937892f3ab0f90d13755a93a7e902e821da8938dd2bacf", + "polyglot/python.md": "a9fc8330cbc78953244b94a170197038a299a5a25fa78c38c7bfb451fd67d345", "polyglot/rust-cloud-quickstart.md": "2303434fc9302a81a8381ad4836423ef9952eb3201a4574c432254e3cb68c5f3", "polyglot/rust.md": "32de05a771b5ee6d8cf54fdd408222372995ce29c8be63102abe58b977ac8ef0", "polyglot/server-api-reference.md": "e94af77a13b341d6fdc9941d4ee94e5053ab932d2e77069b238eb33351414e83", diff --git a/i18n/zh-Hans/docusaurus-plugin-content-docs/current/features/heartbeats.md b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/features/heartbeats.md index 5020db80337..57abfead660 100644 --- a/i18n/zh-Hans/docusaurus-plugin-content-docs/current/features/heartbeats.md +++ b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/features/heartbeats.md @@ -40,6 +40,10 @@ final class PollRemoteJob extends Activity 多语言 Worker 可通过 HTTP Worker 桥接发送心跳,无需构造 PHP 活动类。端点见 [Worker 协议](/docs/polyglot/worker-protocol)。 +单个阻塞调用可能需要专门的辅助线程发送心跳。这表示进程仍然存活,不代表工作有进展。 +请为调用设置独立且有限的截止时间,并在调用完成或失去执行权限时停止辅助线程。 +Python Worker 应遵循[上下文捕获与取消示例](../polyglot/python.md#heartbeat-helper-thread)。 + ## 发送节奏与确认 {#heartbeat-cadence-and-receipts} 对于排队活动,第一个心跳截止时间从运行时领取时开始,早于任务交付和用户代码执行。已记录的心跳将下一个截止时间设为其运行时时间加上 `heartbeatTimeout`。发送请求或收到响应都不会重新开始一个完整窗口。参见[心跳超时](./timeouts.md#heartbeat-timeout)。 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 d2c4b91a5f4..7ffcaf59fe5 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 @@ -874,6 +874,19 @@ async def validate(data: dict) -> dict: 请限制下游 I/O 的超时时间,并为 CPU 密集型任务使用单独隔离的 Worker 进程。 详见 [SDK 执行与关闭参考](https://python.durable-workflow.com/reference/worker/)。 +### 从辅助线程发送心跳 {#heartbeat-helper-thread} + +对于长时间的阻塞调用,请在同步活动内部获取 `ctx = activity.context()`, +再将它传给辅助线程。新线程不会自动继承活动上下文。 +在辅助线程中调用 `ctx.heartbeat_sync(details)`,不要在 Worker 事件循环中调用。 +完整实现见 SDK 参考中的[辅助线程示例](https://python.durable-workflow.com/reference/activity/#heartbeats-during-one-blocking-call)。 + +调用正常返回或抛出异常时,都要停止辅助线程并通过 `join()` 等待其退出。 +如果心跳抛出 `ActivityCancelled` 或 `ActivityLeaseAuthorityLost`, +请向阻塞调用发出协作取消信号,并在返回结果前重新抛出原始异常。 +辅助线程中的异常无法强制中断阻塞的库调用。请为该调用设置有限的截止时间和取消机制, +同时限制心跳请求的超时时间和重试次数。否则,即使实际工作已卡住,辅助线程仍会持续报告存活。 + ## Worker {#worker} `Worker` 向 Server 注册、轮询任务,并派发给你的工作流和活动实现。 diff --git a/i18n/zh-Hans/source-hashes.json b/i18n/zh-Hans/source-hashes.json index d545f965ece..cd5934052fe 100644 --- a/i18n/zh-Hans/source-hashes.json +++ b/i18n/zh-Hans/source-hashes.json @@ -37,7 +37,7 @@ "features/continue-as-new.md": "6b3cc8f8c5375726ff0b2544da01e7206e964908b436544e284068ab67aa3dbb", "features/events.md": "fcb391862938b5e8cf44ad39f213fc3e55b2ecb7c6edebe6a83a1e58a60bf56e", "features/external-payload-storage.md": "acc312fa2f50a43c96e1d235439124d28a7048f0bf3abac34319467fcbf7e898", - "features/heartbeats.md": "38675bb919f56480baf62f6c6588ae168c62544a97d5a97c9486c1264ed7147c", + "features/heartbeats.md": "e3d84178788dff92954e08d08f006def0a991a481f99301facbda8c6ca21a7a0", "features/local-activities.md": "05fca8f2104d8f4e7bd8b48040f5615f18d0ee2795922fb65c56f8d3d70ed204", "features/memo.md": "621aa630e37fbef6f84d761c92f99dc3fe8756879008c659cbad0600eb14fd5d", "features/message-streams.md": "3bce915ed750793b31360d2accc94eebf2c7f075b9769e072f8a2d3d034afad0", @@ -82,7 +82,7 @@ "polyglot/polling-patterns.md": "30875099a23731c6c471b481a771378acc6ff57eed2fda4405a509057534c989", "polyglot/portable-worker-affinity.md": "40973c6a31a76845b4f95e9a505e68ad76abd5174bbdccf37993cdebc8904959", "polyglot/prerelease-history-migration.md": "a57f05f492228a8a67791f9152648a1e5f80856325b78777cf63b6ef49b7413c", - "polyglot/python.md": "9d6f4d4f0d01ec8d6d937892f3ab0f90d13755a93a7e902e821da8938dd2bacf", + "polyglot/python.md": "a9fc8330cbc78953244b94a170197038a299a5a25fa78c38c7bfb451fd67d345", "polyglot/rust-cloud-quickstart.md": "2303434fc9302a81a8381ad4836423ef9952eb3201a4574c432254e3cb68c5f3", "polyglot/rust.md": "32de05a771b5ee6d8cf54fdd408222372995ce29c8be63102abe58b977ac8ef0", "polyglot/server-api-reference.md": "e94af77a13b341d6fdc9941d4ee94e5053ab932d2e77069b238eb33351414e83",