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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ Some examples require extra dependencies. See each sample's directory for specif
* [custom_decorator](custom_decorator) - Custom decorator to auto-heartbeat a long-running activity.
* [custom_metric](custom_metric) - Custom metric to record the workflow type in the activity schedule to start latency.
* [dsl](dsl) - DSL workflow that executes steps defined in a YAML file.
* [eager_wf_start](eager_wf_start) - Run a workflow using Eager Workflow Start
* [encryption](encryption) - Apply end-to-end encryption for all input/output.
* [env_config](env_config) - Load client configuration from TOML files with programmatic overrides.
* [gevent_async](gevent_async) - Combine gevent and Temporal.
Expand Down
16 changes: 16 additions & 0 deletions eager_wf_start/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Eager Workflow Start

This sample shows how to create a workflow that uses Eager Workflow Start.

The target use case is workflows whose first task needs to execute quickly (ex: payment verification in an online checkout workflow). That work typically can't be done directly in the workflow (ex: using web APIs, databases, etc.), and also needs to avoid the overhead of dispatching another task. Using a Local Activity suffices both needs, which this sample demonstrates.

You can read more about Eager Workflow Start in our:

- [Eager Workflow Start blog](https://temporal.io/blog/improving-latency-with-eager-workflow-start)
- [Worker Performance Docs](https://docs.temporal.io/develop/worker-performance#eager-workflow-start)

To run, first see the main [README.md](../README.md) for prerequisites.

Then run the sample via:

uv run eager_wf_start/run.py
Empty file added eager_wf_start/__init__.py
Empty file.
6 changes: 6 additions & 0 deletions eager_wf_start/activities.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from temporalio import activity


@activity.defn()
async def greeting(name: str) -> str:
return f"Hello {name}!"
42 changes: 42 additions & 0 deletions eager_wf_start/run.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import asyncio
import uuid

from temporalio.client import Client
from temporalio.worker import Worker

from eager_wf_start.activities import greeting
from eager_wf_start.workflows import EagerWorkflow

TASK_QUEUE = "eager-wf-start-task-queue"


async def main():

# Note that the worker and client run in the same process and share the same client connection.
client = await Client.connect("localhost:7233")
worker = Worker(
client,
task_queue=TASK_QUEUE,
workflows=[EagerWorkflow],
activities=[greeting],
)

# Run worker in the background
async with worker:
# Start workflow(s) while worker is running
wf_handle = await client.start_workflow(
EagerWorkflow.run,
"Temporal",
id=f"eager-workflow-id-{uuid.uuid4()}",
task_queue=TASK_QUEUE,
request_eager_start=True,
)

# This is an internal flag not intended to be used publicly.
# It is used here purely to display that the workflow was eagerly started.
print(f"Workflow eagerly started: {wf_handle.__temporal_eagerly_started}")
print(await wf_handle.result())


if __name__ == "__main__":
asyncio.run(main())
15 changes: 15 additions & 0 deletions eager_wf_start/workflows.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from datetime import timedelta

from temporalio import workflow

with workflow.unsafe.imports_passed_through():
from eager_wf_start.activities import greeting


@workflow.defn
class EagerWorkflow:
@workflow.run
async def run(self, name: str) -> str:
return await workflow.execute_local_activity(
greeting, name, schedule_to_close_timeout=timedelta(seconds=5)
)
2 changes: 2 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ async def env(request) -> AsyncGenerator[WorkflowEnvironment, None]:
dev_server_extra_args=[
"--dynamic-config-value",
"frontend.enableExecuteMultiOperation=true",
"--dynamic-config-value",
"system.enableEagerWorkflowStart=true",
]
)
elif env_type == "time-skipping":
Expand Down
Empty file.
29 changes: 29 additions & 0 deletions tests/eager_wf_start/workflow_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import uuid

from temporalio.client import Client
from temporalio.worker import Worker

from eager_wf_start.activities import greeting
from eager_wf_start.workflows import EagerWorkflow


async def test_eager_wf_start(client: Client):
task_queue_name = str(uuid.uuid4())

async with Worker(
client,
task_queue=task_queue_name,
workflows=[EagerWorkflow],
activities=[greeting],
):
handle = await client.start_workflow(
EagerWorkflow.run,
"Temporal",
id=f"workflow-{uuid.uuid4()}",
task_queue=task_queue_name,
request_eager_start=True,
)
print("HANDLE", handle.__temporal_eagerly_started)
assert handle.__temporal_eagerly_started
result = await handle.result()
assert result == "Hello Temporal!"
Loading