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
26 changes: 17 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ npm run build
## Translations

English is the default locale. Ukrainian is available under `/uk/`. Spanish
onboarding and core guides are available under `/es/`. Untranslated reference
onboarding and core guides are available under `/es/`, and Brazilian Portuguese
under `/pt-BR/`. Untranslated reference
pages show the English text with a language notice and a link to the English
route. Blog articles and versioned 1.x documentation remain in English.

Expand All @@ -36,6 +37,7 @@ Preview one locale with:
```bash
npm run start -- --locale uk
npm run start -- --locale es
npm run start -- --locale pt-BR
```

Translate current docs in `i18n/<locale>/docusaurus-plugin-content-docs/current/`
Expand All @@ -44,7 +46,9 @@ English source file paths, examples, commands, API names and explicit heading
anchors intact. Ukrainian keeps workflow, activity, worker, signal, timer,
query, update and saga as English technical terms. Spanish uses workflow and
worker, with actividad, señal, temporizador, consulta and actualización in
prose. Never translate identifiers in code, protocol fields or type names.
prose. Brazilian Portuguese keeps workflow, worker, namespace and replay, with
atividade, sinal, temporizador, consulta and atualização in prose. Never
translate identifiers in code, protocol fields or type names.

Use Docusaurus translation markers for component text. Run
`npm run write-translations -- --locale uk` to extract new messages, then
Expand All @@ -54,18 +58,21 @@ all locales with `npm run build` before submitting a change.
When changing an English guide that already has a translation, review and
update that translation in the same pull request. Review the prose for fluent
language and the technical contract for accuracy. Keep executable code blocks
identical to the English source. The build checks this for Spanish. If a
identical to the English source. The build checks this for Spanish and
Brazilian Portuguese. If a
translation cannot be brought current, remove the stale translated file so
readers see the current English source and the fallback notice. Artifact
version placeholders stay shared with English and update automatically.

The documentation maintainers own translation upkeep. The existing build also
compares reviewed English source hashes for Spanish and reports the guides
compares reviewed English source hashes for Spanish and Brazilian Portuguese
and reports the guides
needing review. Prose edits produce a notice, while changed executable examples
must still match. After reviewing and
updating the translation, run `node scripts/check-doc-translations.js --record-review`
and commit `i18n/es/source-hashes.json` with it. This command still checks the
code blocks. Recording hashes alone does not review the prose.
and commit the affected `i18n/<locale>/source-hashes.json` files with it.
This command still checks the code blocks. Recording hashes alone does not
review the prose.

The pinned Docusaurus 3.10.2 utility patch resolves relative Markdown links
between translated and English fallback files. It uses Docusaurus's document
Expand All @@ -76,9 +83,10 @@ Docusaurus if the upstream resolver handles these cases.
For a new locale, qualify installation, a completed first workflow, core
concepts, safe recovery, navigation, search, language switching and fallback
before publication. Check representative pages in a browser, including mobile,
and verify canonical and alternate-language links. Spanish is the first
expansion in [#169](https://github.com/durable-workflow/durable-workflow.github.io/issues/169).
Portuguese (Brazil), Simplified Chinese and Japanese remain subsequent stages,
and verify canonical and alternate-language links. Spanish and Brazilian
Portuguese are the first expansions in
[#169](https://github.com/durable-workflow/durable-workflow.github.io/issues/169).
Simplified Chinese and Japanese remain subsequent stages,
subject to audience evidence and language review. Country totals alone do not
establish a reader's preferred language.

Expand Down
6 changes: 3 additions & 3 deletions docs/how-it-works.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ User workflow code lives in `handle()`, which is an ordinary method that calls t

By calling multiple activities, a workflow can orchestrate the results between each of them. The execution of the workflow and the durable steps it schedules are interleaved: the workflow reaches an activity call, suspends until that activity completes, and then continues execution from where it left off.

If a workflow fails, the events leading up to the failure are replayed to rebuild the current state. This allows the workflow to pick up where it left off, with the same inputs and outputs as before, ensuring determinism.
If a workflow worker crashes, committed events are replayed to rebuild the current state. This allows the workflow to pick up where it left off, with the same inputs and outputs as before, ensuring determinism. An unhandled workflow failure makes the run terminal; replay does not retry a failed run.

Ordinary activities are durable queued work in v2. Explicit
[local activities](./features/local-activities.md) run short activity work in
Expand Down Expand Up @@ -69,7 +69,7 @@ class MyWorkflow extends Workflow
return [
activity(TestActivity::class),
activity(TestOtherActivity::class),
fn () => all([
all([
fn () => activity(TestParallelActivity::class),
fn () => activity(TestParallelOtherActivity::class),
]),
Expand Down Expand Up @@ -97,7 +97,7 @@ import ThemedImage from '@site/src/components/ThemedImage';
3. At this point, the workflow enters the event sourcing replay loop. This is where it goes back to the database and looks at the event stream to rebuild the current state. This is necessary because the workflow is not a long running process. The workflow exits while any activities are running and then is dispatched again after completion.
4. Once the event stream has been replayed, the workflow continues to the next activity, `TestOtherActivity`, and starts it by dispatching it as a queued job. Again, once `TestOtherActivity` has completed, it saves the result to the database and returns control to the workflow by dispatching it as a queued job.
5. The workflow then enters the event sourcing replay loop again, rebuilding the current state from the event stream.
6. Next, the workflow starts two parallel activities, `TestParallelActivity` and `TestOtherParallelActivity`. Both activities are dispatched. Once they have completed, they save the results to the database and return control to the workflow.
6. Next, the workflow starts two parallel activities, `TestParallelActivity` and `TestParallelOtherActivity`. Both activities are dispatched. Once they have completed, they save the results to the database and return control to the workflow.
7. Finally, the workflow enters the event sourcing replay loop one last time to rebuild the current state from the event stream. This completes the execution of the workflow.

## Determinism
Expand Down
3 changes: 2 additions & 1 deletion docusaurus.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,12 @@ const config = {

i18n: {
defaultLocale: 'en',
locales: ['en', 'uk', 'es'],
locales: ['en', 'uk', 'es', 'pt-BR'],
localeConfigs: {
en: {label: 'English', htmlLang: 'en'},
uk: {label: 'Українська', htmlLang: 'uk'},
es: {label: 'Español', htmlLang: 'es'},
'pt-BR': {label: 'Português (Brasil)', htmlLang: 'pt-BR'},
},
},

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ de actividad, se suspende hasta recibir su resultado y continúa desde ese punto

Para recuperar una tarea tras un fallo, el motor reproduce los eventos
confirmados y reconstruye el estado con las mismas entradas y salidas.
Un fallo no controlado del workflow deja el run en un estado terminal.
El replay no vuelve a intentar un run fallido.

En v2, las actividades ordinarias son tareas duraderas en cola y pueden
ejecutarse en cualquier worker compatible. Las
Expand Down Expand Up @@ -100,7 +102,7 @@ class MyWorkflow extends Workflow
return [
activity(TestActivity::class),
activity(TestOtherActivity::class),
fn () => all([
all([
fn () => activity(TestParallelActivity::class),
fn () => activity(TestParallelOtherActivity::class),
]),
Expand Down
2 changes: 1 addition & 1 deletion i18n/es/source-hashes.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"constraints/workflow-constraints.md": "a69c8a118dc790a5d7b6c91806cb7ceca3015004a0fe549aee3094b09cbf17ad",
"defining-workflows/workflows.md": "a0cc26ae208ad3cee612f49e8db41324ee18f700fe67d9f533e48c700df5c386",
"failures-and-recovery.md": "0d2b8c71b7b54a0160c9bd631348a8223c0d05749f7224ec3ea5feaf74a0a3b5",
"how-it-works.md": "119a8aa26802a02aca05e94b80558a4b19b9ac86524ddec0d25416ea24ced688",
"how-it-works.md": "5233792ac55aaf1bd80e3cad88fc3ad23e1eda149255611e257459dd918c52e9",
"installation.md": "1e2e04a8f23414d0e81c72b166700fd6350129ab81b2f22a6205856c23741967",
"introduction.md": "06bf96d164d402d4e376c6308b20f96d324110b2e0cf96c2a1a67b39906072e3",
"polyglot/deployment-modes.md": "ee38a2ca890e6ba5d52fffa1fa0bc65e64a1fc82e47af92463983e523d4e3f49",
Expand Down
32 changes: 32 additions & 0 deletions i18n/pt-BR/code.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"theme.SearchPage.existingResultsTitle": {"message": "Resultados da busca por «{query}»"},
"theme.SearchPage.emptyResultsTitle": {"message": "Buscar na documentação"},
"theme.SearchPage.searchContext.everywhere": {"message": "Em toda a documentação"},
"theme.SearchPage.documentsFound.plurals": {"message": "{count} documento encontrado|{count} documentos encontrados"},
"theme.SearchPage.noResultsText": {"message": "Nenhum documento encontrado"},
"theme.SearchBar.noResultsText": {"message": "Nenhum resultado"},
"theme.SearchBar.seeAllOutsideContext": {"message": "Ver todos os resultados fora de «{context}»"},
"theme.SearchBar.searchInContext": {"message": "Ver todos os resultados em «{context}»"},
"theme.SearchBar.seeAll": {"message": "Ver todos os resultados"},
"theme.SearchBar.label": {"message": "Buscar"},
"docs.translationFallback": {"message": "Esta página está disponível em inglês."},
"docs.readInEnglish": {"message": "Ler em inglês"},
"homepage.tagline": {"message": "Execução durável para PHP, Python e Rust."},
"homepage.getStarted": {"message": "Comece aqui"},
"homepage.deploymentModes": {"message": "Escolha um modelo de implantação"},
"homepage.description": {"message": "Plataforma de execução durável para PHP, Python e Rust, disponível como Cloud gerenciado, Server sob sua administração ou integrada ao Laravel."},
"homepage.cloudDescription": {"message": "Execute workers de PHP, Python ou Rust em um namespace gerenciado enquanto o Durable Workflow opera o ambiente de orquestração."},
"homepage.features.languages.title": {"message": "Desenvolva com PHP, Python ou Rust"},
"homepage.features.languages.description": {"message": "Crie clientes, workflows e atividades com os SDKs oficiais, que compartilham um protocolo público e um formato de dados Avro portável."},
"homepage.features.runtime.title": {"message": "Escolha quem opera o ambiente"},
"homepage.features.runtime.description": {"message": "Use o Durable Workflow Cloud, execute um Server independente ou mantenha o ambiente integrado à sua aplicação Laravel."},
"homepage.features.recovery.title": {"message": "Retome o trabalho após uma falha"},
"homepage.features.recovery.description": {"message": "Histórico durável, replay determinístico, temporizadores, novas tentativas, sinais, atualizações, workflows filhos e sagas permitem dar continuidade a processos longos."},
"promotion.eyebrow": {"message": "Serviço gerenciado · grupo limitado"},
"promotion.title": {"message": "Grupo de lançamento do Durable Workflow Cloud"},
"promotion.requestAccess": {"message": "Solicite acesso antecipado"},
"navbar.github.repository": {"message": "Repositório no GitHub"},
"navbar.github.repositoryStars": {"message": "{repository} ({count} estrelas)"},
"navbar.github.starCount": {"message": "Estrelas no GitHub: {count}"},
"navbar.github.stars": {"message": "Estrelas no GitHub"}
}
25 changes: 25 additions & 0 deletions i18n/pt-BR/docusaurus-plugin-content-docs/current.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"version.label": {"message": "2.0"},
"sidebar.tutorialSidebar.category.Service Mode": {"message": "Modo de serviço"},
"sidebar.tutorialSidebar.category.Service Mode.link.generated-index.description": {"message": "Conecte clientes e workers oficiais de PHP, Python ou Rust ao Cloud ou a um Server sob sua administração. O Cloud inclui o Managed Waterline. Para Server, o Waterline é implantado separadamente."},
"sidebar.tutorialSidebar.category.CLI": {"message": "CLI"},
"sidebar.tutorialSidebar.category.CLI.link.generated-index.description": {"message": "Instale o cliente de operação dw e consulte seus comandos."},
"sidebar.tutorialSidebar.category.SDKs": {"message": "SDKs"},
"sidebar.tutorialSidebar.category.SDKs.link.generated-index.description": {"message": "Crie clientes e workers no modo de serviço com os SDKs oficiais de PHP, Python e Rust."},
"sidebar.tutorialSidebar.category.Embedded": {"message": "Modo integrado"},
"sidebar.tutorialSidebar.category.Embedded.link.generated-index.description": {"message": "Instale, desenvolva, teste e configure workflows em uma aplicação Laravel."},
"sidebar.tutorialSidebar.category.Defining Workflows": {"message": "Definição de workflows"},
"sidebar.tutorialSidebar.category.Defining Workflows.link.generated-index.description": {"message": "Defina workflows, atividades, dados, identificadores e estados no Laravel integrado."},
"sidebar.tutorialSidebar.category.Features": {"message": "Recursos"},
"sidebar.tutorialSidebar.category.Features.link.generated-index.description": {"message": "Escolha mensagens, comandos duráveis, esperas, novas tentativas, versões e limites de histórico no Laravel integrado."},
"sidebar.tutorialSidebar.category.Constraints": {"message": "Restrições"},
"sidebar.tutorialSidebar.category.Constraints.link.generated-index.description": {"message": "Conheça as regras de determinismo e os limites estruturais do modo integrado."},
"sidebar.tutorialSidebar.category.Configuration": {"message": "Configuração"},
"sidebar.tutorialSidebar.category.Configuration.link.generated-index.description": {"message": "Configure armazenamento, conexões, limites e retenção no Laravel integrado."},
"sidebar.tutorialSidebar.category.Run And Operate": {"message": "Execução e operação"},
"sidebar.tutorialSidebar.category.Run And Operate.link.generated-index.description": {"message": "Implante, observe, diagnostique, recupere e mantenha seus workflows."},
"sidebar.tutorialSidebar.category.External Execution And Ingress": {"message": "Execução externa e entrada de solicitações"},
"sidebar.tutorialSidebar.category.External Execution And Ingress.link.generated-index.description": {"message": "Conecte APIs HTTP, workers externos, filas e outras integrações de protocolo."},
"sidebar.tutorialSidebar.category.AI And Automation": {"message": "IA e automação"},
"sidebar.tutorialSidebar.category.AI And Automation.link.generated-index.description": {"message": "Forneça documentação, manifestos, comandos e ferramentas estáveis para agentes e automação."}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
sidebar_position: 3
title: Restrições das atividades
description: Torne os efeitos externos seguros para novas tentativas, expiração de leases e reentrega.
---

# Restrições das atividades {#activity-constraints}

As atividades atravessam a fronteira durável para realizar operações de entrada e saída e efeitos externos. Elas não passam por replay como o código do workflow. São **executadas pelo menos uma vez**, o que significa que novas tentativas, expiração de leases e reentrega podem fazer com que o mesmo trabalho lógico seja observado mais de uma vez.

Esse comportamento faz parte do contrato. Se uma atividade faz uma cobrança, envia um e-mail, grava em outro sistema ou modifica um recurso externo, a operação precisa ser segura para repetição.

## Na prática {#what-this-means-in-practice}

- O identificador padrão para garantir a idempotência de uma execução lógica de atividade é `activity_execution_id`.
- Cada tentativa também recebe seu próprio `activity_attempt_id`.
- Um worker pode concluir uma operação externa, perder seu lease e enviar o resultado depois. O mecanismo pode rejeitar esse relato tardio porque outro worker já venceu a disputa pelo resultado durável, mas o efeito externo pode ter ocorrido.
- O código da atividade pode realizar operações de entrada e saída, consultar o relógio do sistema e usar estado mutável do processo. O código do workflow não pode. Mantenha essa fronteira clara.

## Padrões de idempotência recomendados {#preferred-idempotency-patterns}

Muitas APIs externas aceitam um `Idempotency-Key`. Quando o serviço remoto oferecer esse recurso, use a identidade lógica da atividade fornecida pelo runtime.

- Prefira `activity_execution_id` quando o sistema remoto deve tratar novas tentativas como a mesma solicitação lógica.
- Use `activity_attempt_id` apenas quando o sistema remoto precisa distinguir as tentativas de um mesmo trabalho lógico.

Outros padrões úteis:

- Grave em um recurso externo com nome determinístico ou chave natural.
- Use upserts ou tabelas de deduplicação com um identificador durável como chave.
- Torne a operação naturalmente idempotente, para que a segunda chamada não faça nenhuma alteração.

Muitas operações já são naturalmente idempotentes. Codificar o mesmo vídeo duas vezes ainda produz o mesmo vídeo. Excluir o mesmo arquivo duas vezes não faz nada na segunda chamada.

Algumas operações não são naturalmente idempotentes, mas a duplicação ainda pode ser a falha menos prejudicial. Se você não sabe se um e-mail saiu do provedor, enviar uma cópia pode ser preferível a perder a notificação silenciosamente. Faça essa escolha de forma consciente.

## O que não presumir {#what-not-to-assume}

- Não presuma que uma tentativa de atividade só executa em um worker.
- Não presuma que uma nova tentativa significa que o efeito externo anterior falhou.
- Não presuma que um relato tardio de conclusão significa que a atividade nunca executou.
- Não mova efeitos externos para o código do workflow para evitar novas tentativas. Isso transforma um problema de idempotência em uma falha de determinismo.

Veja [Garantias de execução e idempotência](./execution-guarantees.md) para o contrato completo e [Falhas e recuperação](../failures-and-recovery.md) para o modelo de recuperação disponível ao operador.
Loading
Loading