7.1 Objective
ACAI can now:
Chapter 1 → Core API
Chapter 2 → Planner
Chapter 3 → Retrieval
Chapter 4 → Memory
Chapter 5 → Model Router
Chapter 6 → Verification
Enter fullscreen mode Exit fullscreen mode
The next limitation is that a complex request may require multiple dependent operations.
For example:
"Research a topic, summarize the evidence,
compare the findings, and produce a report."
Enter fullscreen mode Exit fullscreen mode
This is not one simple task.
It can be represented as:
Research
↓
Collect Evidence
↓
Analyze
↓
Compare
↓
Write Report
↓
Verify
Enter fullscreen mode Exit fullscreen mode
Chapter 7 introduces a workflow engine that represents these operations as a task graph.
7.2 From Single Request to Workflow
The previous system was approximately:
User
↓
Planner
↓
Router
↓
Model
↓
Verifier
↓
Response
Enter fullscreen mode Exit fullscreen mode
The new system becomes:
User Goal
↓
Planner
↓
Workflow
↓
Task Graph
↓
Executor
↓
Verification
↓
Final Result
Enter fullscreen mode Exit fullscreen mode
The key idea is:
A complex AI task should be decomposed into smaller executable steps.
7.3 Workflow Graph
A workflow can be represented as a directed graph.
Example:
┌───────────────┐
│ Research │
└───────┬───────┘
│
┌───────▼───────┐
│ Extract Data │
└───────┬───────┘
│
┌───────▼───────┐
│ Analyze │
└───────┬───────┘
│
┌──────┴──────┐
▼ ▼
┌──────────┐ ┌──────────┐
│ Compare │ │ Validate │
└────┬─────┘ └────┬─────┘
│ │
└──────┬───────┘
▼
┌───────────┐
│ Report │
└─────┬─────┘
▼
Verification
Enter fullscreen mode Exit fullscreen mode
Some tasks depend on previous tasks.
Others can execute independently.
7.4 Task Data Model
Create:
app/services/workflow.py
Enter fullscreen mode Exit fullscreen mode
Start with:
from dataclasses import dataclass, field
@dataclass
class Task:
task_id: str
name: str
task_type: str
dependencies: list[str] = field(
default_factory=list
)
status: str = "pending"
result: str | None = None
error: str | None = None
Enter fullscreen mode Exit fullscreen mode
Each task contains:
task_id
name
task_type
dependencies
status
result
error
Enter fullscreen mode Exit fullscreen mode
7.5 Task States
A task should have explicit states.
pending
↓
running
↓
completed
Enter fullscreen mode Exit fullscreen mode
If something fails:
running
↓
failed
Enter fullscreen mode Exit fullscreen mode
A retry can produce:
failed
↓
retrying
↓
running
Enter fullscreen mode Exit fullscreen mode
The state machine is:
┌──────────┐
│ pending │
└────┬─────┘
▼
┌──────────┐
│ running │
└────┬─────┘
┌───┴───┐
▼ ▼
┌─────────┐ ┌────────┐
│complete │ │ failed │
└─────────┘ └───┬────┘
│
▼
retry
Enter fullscreen mode Exit fullscreen mode
7.6 Workflow Container
Add:
from dataclasses import dataclass, field
@dataclass
class Workflow:
workflow_id: str
tasks: dict[str, Task] = field(
default_factory=dict
)
status: str = "pending"
result: str | None = None
Enter fullscreen mode Exit fullscreen mode
Now ACAI can represent:
Workflow
├── Task A
├── Task B
├── Task C
└── Task D
Enter fullscreen mode Exit fullscreen mode
7.7 Adding Tasks
Add:
class WorkflowBuilder:
def __init__(
self,
workflow_id: str,
) -> None:
self.workflow = Workflow(
workflow_id=workflow_id
)
def add_task(
self,
task_id: str,
name: str,
task_type: str,
dependencies: list[str] | None = None,
) -> None:
if task_id in self.workflow.tasks:
raise ValueError(
f"Task already exists: "
f"{task_id}"
)
self.workflow.tasks[task_id] = Task(
task_id=task_id,
name=name,
task_type=task_type,
dependencies=(
dependencies or []
),
)
def build(self) -> Workflow:
return self.workflow
Enter fullscreen mode Exit fullscreen mode
7.8 Example Workflow
Create:
from uuid import uuid4
builder = WorkflowBuilder(
workflow_id=str(uuid4())
)
builder.add_task(
task_id="research",
name="Research topic",
task_type="research",
)
builder.add_task(
task_id="analysis",
name="Analyze evidence",
task_type="analysis",
dependencies=[
"research"
],
)
builder.add_task(
task_id="report",
name="Write report",
task_type="writing",
dependencies=[
"analysis"
],
)
workflow = builder.build()
Enter fullscreen mode Exit fullscreen mode
The dependency graph is:
research
↓
analysis
↓
report
Enter fullscreen mode Exit fullscreen mode
7.9 Dependency Validation
A workflow should reject invalid dependencies.
Add:
def validate_workflow(
workflow: Workflow,
) -> None:
task_ids = set(
workflow.tasks.keys()
)
for task in workflow.tasks.values():
for dependency in task.dependencies:
if dependency not in task_ids:
raise ValueError(
f"Unknown dependency "
f"{dependency} for task "
f"{task.task_id}"
)
Enter fullscreen mode Exit fullscreen mode
This prevents:
Task A
↓
Missing Task X
Enter fullscreen mode Exit fullscreen mode
from reaching execution.
7.10 Circular Dependency Detection
A more dangerous problem is:
Task A
↓
Task B
↓
Task A
Enter fullscreen mode Exit fullscreen mode
This creates a cycle.
Add:
def detect_cycle(
workflow: Workflow,
) -> bool:
visiting = set()
visited = set()
def visit(
task_id: str,
) -> bool:
if task_id in visiting:
return True
if task_id in visited:
return False
visiting.add(task_id)
task = workflow.tasks[task_id]
for dependency in task.dependencies:
if visit(dependency):
return True
visiting.remove(task_id)
visited.add(task_id)
return False
for task_id in workflow.tasks:
if visit(task_id):
return True
return False
Enter fullscreen mode Exit fullscreen mode
Then:
def validate_workflow(
workflow: Workflow,
) -> None:
task_ids = set(
workflow.tasks.keys()
)
for task in workflow.tasks.values():
for dependency in task.dependencies:
if dependency not in task_ids:
raise ValueError(
f"Unknown dependency "
f"{dependency}"
)
if detect_cycle(workflow):
raise ValueError(
"Workflow contains a cycle."
)
Enter fullscreen mode Exit fullscreen mode
7.11 Finding Ready Tasks
The executor needs to determine which tasks can run.
A task is ready when:
status = pending
Enter fullscreen mode Exit fullscreen mode
and every dependency is:
completed
Enter fullscreen mode Exit fullscreen mode
Add:
def get_ready_tasks(
workflow: Workflow,
) -> list[Task]:
ready = []
for task in workflow.tasks.values():
if task.status != "pending":
continue
dependencies_completed = all(
workflow.tasks[
dependency
].status == "completed"
for dependency
in task.dependencies
)
if dependencies_completed:
ready.append(task)
return ready
Enter fullscreen mode Exit fullscreen mode
7.12 Workflow Executor
Create:
class WorkflowExecutor:
async def execute(
self,
workflow: Workflow,
) -> Workflow:
validate_workflow(workflow)
workflow.status = "running"
while True:
ready_tasks = get_ready_tasks(
workflow
)
if not ready_tasks:
unfinished = [
task
for task
in workflow.tasks.values()
if task.status
not in {
"completed",
"failed",
}
]
if unfinished:
raise RuntimeError(
"Workflow cannot make "
"further progress."
)
break
for task in ready_tasks:
await self.execute_task(
task,
workflow,
)
workflow.status = "completed"
return workflow
Enter fullscreen mode Exit fullscreen mode
7.13 Task Execution
Add:
async def execute_task(
self,
task: Task,
workflow: Workflow,
) -> None:
task.status = "running"
try:
result = await self.run_task(
task,
workflow,
)
task.result = result
task.status = "completed"
except Exception as exc:
task.error = str(exc)
task.status = "failed"
workflow.status = "failed"
raise
Enter fullscreen mode Exit fullscreen mode
7.14 Task Runner
For the first prototype:
async def run_task(
self,
task: Task,
workflow: Workflow,
) -> str:
if task.task_type == "research":
return (
"Research task completed."
)
if task.task_type == "analysis":
return (
"Analysis task completed."
)
if task.task_type == "writing":
return (
"Writing task completed."
)
return (
f"Task {task.name} completed."
)
Enter fullscreen mode Exit fullscreen mode
This is intentionally a mock implementation.
Later it will call:
Research
→ Retrieval Service
Analysis
→ Model Router + Model
Writing
→ Model Router + Model
Verification
→ Verification Service
Enter fullscreen mode Exit fullscreen mode
7.15 Complete Workflow Executor
The prototype can therefore be:
class WorkflowExecutor:
async def execute(
self,
workflow: Workflow,
) -> Workflow:
validate_workflow(workflow)
workflow.status = "running"
while True:
ready_tasks = get_ready_tasks(
workflow
)
if not ready_tasks:
unfinished = [
task
for task
in workflow.tasks.values()
if task.status
not in {
"completed",
"failed",
}
]
if unfinished:
raise RuntimeError(
"Workflow cannot make "
"further progress."
)
break
for task in ready_tasks:
await self.execute_task(
task,
workflow,
)
workflow.status = "completed"
return workflow
async def execute_task(
self,
task: Task,
workflow: Workflow,
) -> None:
task.status = "running"
try:
result = await self.run_task(
task,
workflow,
)
task.result = result
task.status = "completed"
except Exception as exc:
task.error = str(exc)
task.status = "failed"
workflow.status = "failed"
raise
async def run_task(
self,
task: Task,
workflow: Workflow,
) -> str:
if task.task_type == "research":
return (
"Research task completed."
)
if task.task_type == "analysis":
return (
"Analysis task completed."
)
if task.task_type == "writing":
return (
"Writing task completed."
)
return (
f"Task {task.name} completed."
)
Enter fullscreen mode Exit fullscreen mode
7.16 Sequential Execution
For:
Research
↓
Analysis
↓
Report
Enter fullscreen mode Exit fullscreen mode
execution becomes:
Research
↓
COMPLETED
↓
Analysis
↓
COMPLETED
↓
Report
↓
COMPLETED
Enter fullscreen mode Exit fullscreen mode
7.17 Parallel Execution
Consider:
Research
/ \
▼ ▼
Source A Source B
│ │
└────┬─────┘
▼
Analysis
Enter fullscreen mode Exit fullscreen mode
Source A and Source B do not depend on each other.
They can therefore run in parallel.
The architecture becomes:
Research
│
┌──────┴──────┐
▼ ▼
Source A Source B
│ │
└──────┬──────┘
▼
Analysis
Enter fullscreen mode Exit fullscreen mode
7.18 Parallel Task Execution
Python’s asyncio can execute independent asynchronous tasks concurrently.
Add:
import asyncio
Enter fullscreen mode Exit fullscreen mode
Then replace the sequential loop:
for task in ready_tasks:
await self.execute_task(
task,
workflow,
)
Enter fullscreen mode Exit fullscreen mode
with:
await asyncio.gather(
*[
self.execute_task(
task,
workflow,
)
for task in ready_tasks
]
)
Enter fullscreen mode Exit fullscreen mode
Now independent tasks can execute concurrently.
7.19 Why Parallelism Matters
Suppose:
Task A = 5 seconds
Task B = 5 seconds
Enter fullscreen mode Exit fullscreen mode
Sequential execution can take approximately:
5 + 5 = 10 seconds
Enter fullscreen mode Exit fullscreen mode
If they are independent and safely executed concurrently, idealized execution can approach:
max(5, 5) = 5 seconds
Enter fullscreen mode Exit fullscreen mode
Real systems have overhead, rate limits, network latency, and resource constraints, so actual performance must be measured.
7.20 Retry Policy
Real workflows fail.
Possible causes:
Network error
Provider timeout
Temporary API failure
Rate limit
Invalid response
Dependency failure
Enter fullscreen mode Exit fullscreen mode
A task should therefore support bounded retries.
Add:
@dataclass
class Task:
task_id: str
name: str
task_type: str
dependencies: list[str] = field(
default_factory=list
)
status: str = "pending"
result: str | None = None
error: str | None = None
attempts: int = 0
max_attempts: int = 3
Enter fullscreen mode Exit fullscreen mode
7.21 Retry Implementation
async def execute_task(
self,
task: Task,
workflow: Workflow,
) -> None:
while task.attempts < task.max_attempts:
task.attempts += 1
task.status = "running"
try:
result = await self.run_task(
task,
workflow,
)
task.result = result
task.status = "completed"
return
except Exception as exc:
task.error = str(exc)
if (
task.attempts
>= task.max_attempts
):
task.status = "failed"
raise
task.status = "retrying"
Enter fullscreen mode Exit fullscreen mode
This gives:
Attempt 1
↓
Fail
↓
Attempt 2
↓
Fail
↓
Attempt 3
↓
Success / Failure
Enter fullscreen mode Exit fullscreen mode
7.22 Retry Is Not Always Correct
Retries should not be automatic for every error.
For example:
Invalid input
Enter fullscreen mode Exit fullscreen mode
may not become valid by repeating the same request.
But:
Temporary network failure
Enter fullscreen mode Exit fullscreen mode
might succeed on retry.
Therefore future versions should classify errors:
Transient
Permanent
Unknown
Enter fullscreen mode Exit fullscreen mode
Then retry only appropriate failures.
7.23 Timeout Protection
A task that never completes can block an entire workflow.
Use:
import asyncio
Enter fullscreen mode Exit fullscreen mode
and:
result = await asyncio.wait_for(
self.run_task(
task,
workflow,
),
timeout=60,
)
Enter fullscreen mode Exit fullscreen mode
This creates a maximum execution window.
7.24 Workflow Failure Handling
Suppose:
Task A → completed
Task B → failed
Task C → depends on B
Enter fullscreen mode Exit fullscreen mode
Task C cannot safely execute.
Therefore:
A → COMPLETE
B → FAILED
C → BLOCKED
Enter fullscreen mode Exit fullscreen mode
The system should distinguish:
failed
Enter fullscreen mode Exit fullscreen mode
from:
blocked
Enter fullscreen mode Exit fullscreen mode
Add:
pending
running
retrying
completed
failed
blocked
Enter fullscreen mode Exit fullscreen mode
7.25 Workflow Result
The workflow can produce a final result from completed tasks.
Example:
def collect_results(
workflow: Workflow,
) -> dict[str, str]:
return {
task.task_id: task.result
for task in workflow.tasks.values()
if task.result is not None
}
Enter fullscreen mode Exit fullscreen mode
Then:
Workflow
↓
Task Results
↓
Result Aggregation
↓
Final Answer
Enter fullscreen mode Exit fullscreen mode
7.26 Integrating Verification
Workflow execution should not end immediately after generation.
A final verification task should be added.
Example:
Research
↓
Analysis
↓
Draft
↓
Verification
↓
Final
Enter fullscreen mode Exit fullscreen mode
The verification task can inspect:
Draft
+
Evidence
+
Original User Goal
Enter fullscreen mode Exit fullscreen mode
Then return:
PASS
Enter fullscreen mode Exit fullscreen mode
or:
REVISION_REQUIRED
Enter fullscreen mode Exit fullscreen mode
7.27 Workflow-Level Verification
Architecture:
USER GOAL
│
▼
PLANNER
│
▼
TASK GRAPH
│
┌──────────┼──────────┐
▼ ▼ ▼
Task A Task B Task C
│ │ │
└──────────┼──────────┘
▼
Draft
│
▼
Verification
│
┌────┴────┐
▼ ▼
PASS REVISE
│ │
▼ ▼
Final Retry
Enter fullscreen mode Exit fullscreen mode
7.28 Agent Execution
At this point ACAI begins to resemble an agentic workflow system.
But an important distinction should be maintained:
Agent
≠
Uncontrolled autonomous process
Enter fullscreen mode Exit fullscreen mode
A practical agent should have:
Goal
+
Tools
+
State
+
Constraints
+
Termination Conditions
Enter fullscreen mode Exit fullscreen mode
7.29 Agent State
Create:
@dataclass
class AgentState:
goal: str
current_task: str | None = None
completed_tasks: list[str] = field(
default_factory=list
)
failed_tasks: list[str] = field(
default_factory=list
)
observations: list[str] = field(
default_factory=list
)
Enter fullscreen mode Exit fullscreen mode
The agent can now maintain execution state.
7.30 Agent Loop
The conceptual loop is:
Goal
↓
Observe
↓
Plan
↓
Act
↓
Observe Result
↓
Verify
↓
Continue / Stop
Enter fullscreen mode Exit fullscreen mode
Implementation:
async def run_agent(
goal: str,
) -> AgentState:
state = AgentState(
goal=goal
)
while True:
# Observe
observation = (
"Current workflow state"
)
state.observations.append(
observation
)
# Plan
task = choose_next_task(
state
)
if task is None:
break
# Act
state.current_task = task
result = await execute_agent_task(
task
)
# Record
state.completed_tasks.append(
task
)
return state
Enter fullscreen mode Exit fullscreen mode
This is a simplified demonstration.
7.31 Termination Conditions
An agent must have clear stopping conditions.
For example:
Goal achieved
OR
Maximum steps reached
OR
Maximum time reached
OR
No valid action available
OR
Critical failure
Enter fullscreen mode Exit fullscreen mode
Without termination conditions:
Agent
↓
Action
↓
Action
↓
Action
↓
...
Enter fullscreen mode Exit fullscreen mode
could continue indefinitely.
7.32 Maximum Steps
Add:
MAX_AGENT_STEPS = 10
Enter fullscreen mode Exit fullscreen mode
Then:
for step in range(
MAX_AGENT_STEPS
):
...
Enter fullscreen mode Exit fullscreen mode
This gives the system a hard upper bound.
7.33 Tool Execution
A future ACAI agent can use controlled tools:
Retrieval
File Search
Calculator
Code Executor
Database
External API
Model
Enter fullscreen mode Exit fullscreen mode
The architecture should be:
Agent
│
▼
Tool Selection
│
▼
Permission Check
│
▼
Tool Execution
│
▼
Result Validation
Enter fullscreen mode Exit fullscreen mode
The permission layer is important.
An agent should not automatically receive unrestricted access to arbitrary systems.
7.34 Tool Registry
Create:
class ToolRegistry:
def __init__(self) -> None:
self.tools = {}
def register(
self,
name: str,
function,
) -> None:
self.tools[name] = function
def get(
self,
name: str,
):
return self.tools.get(name)
def list_tools(self) -> list[str]:
return list(
self.tools.keys()
)
Enter fullscreen mode Exit fullscreen mode
Example:
registry = ToolRegistry()
registry.register(
"retrieval",
retrieval_service,
)
Enter fullscreen mode Exit fullscreen mode
Now the agent can discover available tools through a controlled registry.
7.35 Permission Layer
Before tool execution:
Agent
↓
Requested Tool
↓
Permission Policy
↓
Allowed?
┌──┴──┐
YES NO
│ │
▼ ▼
Run Reject
Enter fullscreen mode Exit fullscreen mode
Example:
class ToolPolicy:
def __init__(
self,
allowed_tools: set[str],
) -> None:
self.allowed_tools = (
allowed_tools
)
def allowed(
self,
tool_name: str,
) -> bool:
return (
tool_name
in self.allowed_tools
)
Enter fullscreen mode Exit fullscreen mode
This makes tool access explicit.
7.36 Observability
Workflow execution needs detailed logs.
For each task:
workflow_id
task_id
task_type
start_time
end_time
duration
status
attempt
error
Enter fullscreen mode Exit fullscreen mode
Example:
event = {
"workflow_id":
workflow.workflow_id,
"task_id":
task.task_id,
"status":
task.status,
"attempt":
task.attempts,
}
Enter fullscreen mode Exit fullscreen mode
These events can later be sent to a logging system.
7.37 Workflow Tests
Create:
tests/test_workflow.py
Enter fullscreen mode Exit fullscreen mode
Add:
import pytest
from app.services.workflow import (
Task,
Workflow,
WorkflowBuilder,
get_ready_tasks,
validate_workflow,
)
Enter fullscreen mode Exit fullscreen mode
Test task dependencies:
def test_ready_tasks():
workflow = Workflow(
workflow_id="test"
)
workflow.tasks["a"] = Task(
task_id="a",
name="A",
task_type="general",
)
workflow.tasks["b"] = Task(
task_id="b",
name="B",
task_type="general",
dependencies=["a"],
)
ready = get_ready_tasks(
workflow
)
assert len(ready) == 1
assert ready[0].task_id == "a"
Enter fullscreen mode Exit fullscreen mode
7.38 Dependency Validation Test
def test_invalid_dependency():
workflow = Workflow(
workflow_id="test"
)
workflow.tasks["a"] = Task(
task_id="a",
name="A",
task_type="general",
dependencies=["missing"],
)
with pytest.raises(ValueError):
validate_workflow(
workflow
)
Enter fullscreen mode Exit fullscreen mode
7.39 Cycle Detection Test
def test_cycle_detection():
workflow = Workflow(
workflow_id="test"
)
workflow.tasks["a"] = Task(
task_id="a",
name="A",
task_type="general",
dependencies=["b"],
)
workflow.tasks["b"] = Task(
task_id="b",
name="B",
task_type="general",
dependencies=["a"],
)
with pytest.raises(ValueError):
validate_workflow(
workflow
)
Enter fullscreen mode Exit fullscreen mode
7.40 End-to-End Workflow Test
import pytest
from app.services.workflow import (
WorkflowBuilder,
WorkflowExecutor,
)
@pytest.mark.asyncio
async def test_workflow_execution():
builder = WorkflowBuilder(
workflow_id="demo"
)
builder.add_task(
task_id="research",
name="Research",
task_type="research",
)
builder.add_task(
task_id="analysis",
name="Analysis",
task_type="analysis",
dependencies=[
"research"
],
)
workflow = builder.build()
executor = WorkflowExecutor()
result = await executor.execute(
workflow
)
assert result.status == "completed"
assert (
result.tasks["research"]
.status
== "completed"
)
assert (
result.tasks["analysis"]
.status
== "completed"
)
Enter fullscreen mode Exit fullscreen mode
7.41 Run Tests
Run:
pytest
Enter fullscreen mode Exit fullscreen mode
You should now have coverage for:
API
Planner
Retrieval
Memory
Router
Verification
Workflow
Enter fullscreen mode Exit fullscreen mode
7.42 Full ACAI Architecture After Chapter 7
USER
│
▼
FastAPI API
│
▼
ORCHESTRATOR
│
▼
PLANNER
│
▼
WORKFLOW GRAPH
│
┌────────────────┼────────────────┐
▼ ▼ ▼
TASK A TASK B TASK C
│ │ │
└────────────────┼────────────────┘
│
▼
MODEL ROUTER
│
▼
MODEL SERVICE
│
▼
GENERATION
│
▼
VERIFICATION
│
┌──────┴──────┐
▼ ▼
PASS REVISE
│ │
▼ ▼
RESULT RETRY
Enter fullscreen mode Exit fullscreen mode
7.43 What ACAI Can Do Now
After Chapter 7, the architecture can conceptually:
[✓] Receive a request
[✓] Analyze the task
[✓] Retrieve information
[✓] Use memory
[✓] Select a model
[✓] Create multiple tasks
[✓] Handle dependencies
[✓] Execute independent tasks concurrently
[✓] Retry bounded failures
[✓] Apply timeouts
[✓] Verify outputs
[✓] Produce a final result
Enter fullscreen mode Exit fullscreen mode
This is substantially more capable than a simple:
Prompt → Model → Answer
Enter fullscreen mode Exit fullscreen mode
pipeline.
7.44 What It Still Cannot Claim
The architecture should not yet be described as:
AGI
Human-level intelligence
Fully autonomous intelligence
Guaranteed factual AI
Self-improving superintelligence
Enter fullscreen mode Exit fullscreen mode
Those claims would require evidence far beyond the architecture described here.
A technically defensible description is:
ACAI is a modular AI orchestration architecture that combines planning, retrieval, memory, model routing, workflow execution, and output verification.
7.45 Next Chapter
The architecture now has execution capabilities.
The next major requirement is persistent data and production infrastructure.
Currently:
Memory
→ In-memory Python objects
Workflow
→ Runtime objects
Logs
→ Basic application logging
Enter fullscreen mode Exit fullscreen mode
These disappear when the process stops unless persistent storage is added.
Therefore the next chapter will introduce:
Chapter 8 — Persistent Storage, API Reliability, and Production Infrastructure
The architecture will move toward:
ACAI
│
┌──────────┼──────────┐
▼ ▼ ▼
Compute Storage Observability
│ │ │
▼ ▼ ▼
Workers Database Metrics
│
┌─────┴─────┐
▼ ▼
Memory Workflows
Enter fullscreen mode Exit fullscreen mode
The next stage will cover:
Database schema
Persistent memory
Workflow persistence
Request IDs
Error handling
Rate limiting
Caching
Background jobs
Health checks
Production configuration
Enter fullscreen mode Exit fullscreen mode
End of Chapter 7