DocuStore.io
Architecture

Temporal Workflows

How DocuStore uses Temporal for durable workflow orchestration, automatic retries, and observable processing pipelines.

Every long-running operation in DocuStore -- PDF parsing, embedding generation, LLM summarization, compound extraction -- is orchestrated by Temporal. This provides automatic retries, timeout handling, observability, and crash recovery without custom retry logic.

Architecture

The system runs three independent worker processes:

WorkerRoleTask Queue
API serverHandles HTTP requests, starts workflows--
Pipeline workerSubscribes to EventStoreDB, triggers workflows--
Temporal workerExecutes workflows and activitiesartifact_processing, llm_processing

The pipeline worker detects domain events from the EventStoreDB subscription and starts the appropriate Temporal workflow. The Temporal worker polls for tasks and executes the actual processing logic.

# Start all three processes for local development
make run                # API server
make run-workflow-worker # Pipeline worker (EventStoreDB → Temporal)
make run-temporal-worker # Temporal worker (executes activities)

Event Pipeline

Domain events trigger workflows in a cascade. Each workflow completes by saving results to the aggregate, which emits a new event, which triggers the next workflow:

Artifact.Created
  └─ ArtifactProcessingWorkflow (PDF parse → page creation)

Page.Created
  └─ ExtractCompoundMentionsWorkflow (OCSR)

Page.TextMentionUpdated
  ├─ TextEmbeddingWorkflow
  │    └─ Page.TextEmbeddingGenerated
  │         └─ SummarizationWorkflow
  │              └─ Page.SummaryCandidateUpdated
  │                   ├─ TriggerArtifactSummarizationUseCase
  │                   └─ PageSummaryEmbeddingWorkflow
  └─ NERExtractionWorkflow
       └─ Page.TagMentionsUpdated
            └─ ArtifactTagAggregationWorkflow

Page.CompoundMentionsUpdated
  └─ SmilesEmbeddingWorkflow

Idempotency

Workflow IDs are derived deterministically from entity IDs:

WorkflowWorkflow ID Pattern
Artifact processingartifact-processing-{artifact_id}
Text embeddingtext-embedding-{page_id}
Compound extractioncompound-extraction-{page_id}
NER extractionner-extraction-{page_id}
Page summarizationpage-summarization-{page_id}
Artifact summarizationartifact-summarization-{artifact_id}

All workflows use the ALLOW_DUPLICATE reuse policy, meaning that re-triggering the same workflow for the same entity is a safe no-op if the workflow is already running.

Port-Based Design

The application layer depends on an abstract WorkflowOrchestrator port:

class WorkflowOrchestrator(Protocol):
    async def start_embedding_workflow(self, page_id: UUID) -> None: ...
    async def start_compound_extraction_workflow(self, page_id: UUID) -> None: ...
    async def start_ner_extraction_workflow(self, page_id: UUID) -> None: ...
    async def start_artifact_summarization_workflow(self, artifact_id: UUID) -> None: ...
    # ... additional workflow methods

The TemporalWorkflowOrchestrator in the infrastructure layer implements this port using the Temporal Python SDK. The application layer never imports Temporal directly, so the orchestration backend could be swapped to Celery, AWS Step Functions, or any other system without changing business logic.

Task Queues

DocuStore uses two task queues to control concurrency:

QueuePurposeMax Concurrent Activities
artifact_processingCPU-bound work (parsing, embedding, OCSR)Configurable via TEMPORAL_MAX_CONCURRENT_ACTIVITIES
llm_processingLLM inference (summarization, NER)Configurable via TEMPORAL_MAX_CONCURRENT_LLM_ACTIVITIES

Separating LLM activities onto their own queue prevents slow LLM calls from blocking fast embedding and parsing tasks. For local development with Ollama, TEMPORAL_MAX_CONCURRENT_LLM_ACTIVITIES=2 prevents memory exhaustion.

Retry Configuration

Activities are configured with appropriate timeouts and retry policies:

Activity TypeTimeoutMax RetriesBackoff
PDF parsing10 min310s to 120s
Text embedding5 min35s to 60s
Compound extraction (OCSR)10 min310s to 120s
NER extraction10 min310s to 120s
Page summarization15 min310s to 120s
Artifact summarization60 min330s to 300s
Summary embedding5 min35s to 60s

Configuration

VariableDefaultDescription
TEMPORAL_ADDRESSlocalhost:7233Temporal server address
TEMPORAL_MAX_CONCURRENT_ACTIVITIES10Max parallel activities on the main queue
TEMPORAL_LLM_TASK_QUEUEllm_processingTask queue name for LLM activities
TEMPORAL_MAX_CONCURRENT_LLM_ACTIVITIES2Max parallel LLM activities (Ollama: 1-2, cloud: 5-10)

Observability

Every workflow execution is visible in the Temporal UI at http://localhost:8080 (default). You can inspect:

  • Workflow execution history (started, activities, completed/failed)
  • Activity inputs, outputs, and retry attempts
  • Pending activities and their timeouts
  • Workflow search by ID pattern (e.g., all text-embedding-* workflows)