Skip to main content
Version: 2.0 prerelease

Continue As New

The Continue As New pattern allows a running workflow to restart itself with new arguments. This is useful when you need to:

  • Prevent unbounded workflow history growth.
  • Model iterative loops or recursive workflows.
  • Split long-running workflows into smaller, manageable executions while preserving continuity.

Using continueAsNew

To restart a workflow as new, call the helper function continueAsNew(...) from within the workflow’s handle() method. continueAsNew() is a first-class run transition.

use function Workflow\V2\activity;
use function Workflow\V2\continueAsNew;
use Workflow\V2\Workflow;

class CounterWorkflow extends Workflow
{
public function handle(int $count = 0, int $max = 3)
{
$result = activity(CountActivity::class, $count);

if ($count >= $max) {
return [
‘count’ => $result,
‘workflow_id’ => $this->workflowId(),
‘run_id’ => $this->runId(),
];
}

return continueAsNew($count + 1, $max);
}
}

In this example:

  • The workflow executes an activity each iteration.
  • If the maximum count has not been reached, it continues as new with incremented arguments.
  • The final result is returned only when the loop completes.

When a workflow continues as new:

  • The instance id stays stable across the chain; WorkflowStub::runId() moves forward to the newest run.
  • The continued run closes as completed / continued and the next run starts immediately with a fresh run id.
  • Signals, queries, updates, and operator commands always resolve the newest durable run for that instance — callers do not need to track run ids across continue-as-new boundaries.

Long-lived loops can shed history without inventing a new public workflow id every time the run rolls forward.

History Budget

Workflow code can observe its current history length and a continue-as-new suggestion flag through explicit runtime context. This lets long-lived loops hand off deliberately before they hit history-budget cliffs.

use function Workflow\V2\activity;
use function Workflow\V2\continueAsNew;
use Workflow\V2\Workflow;

class PollingWorkflow extends Workflow
{
public function handle(int $iteration = 0)
{
$result = activity(PollActivity::class);

if ($this->shouldContinueAsNew()) {
return continueAsNew($iteration + 1);
}

return ['result' => $result, 'iteration' => $iteration];
}
}

Available methods

MethodReturn typeDescription
$this->historyLength()intNumber of history events in the current run
$this->historySize()intTotal size of history events in bytes
$this->shouldContinueAsNew()booltrue when the run exceeds the configured event count or byte size budget

Configuration

The continue-as-new recommendation thresholds are configurable:

// config/workflows.php
'v2' => [
'history_budget' => [
'continue_as_new_event_threshold' => 10000,
'continue_as_new_size_bytes_threshold' => 5242880, // 5 MB
],
],

shouldContinueAsNew() returns true when either threshold is crossed. Run summaries also track history_event_count, history_size_bytes, and continue_as_new_recommended so Waterline can flag long-lived runs in fleet views.

Metadata Carry-Forward

When a workflow continues as new, the new run inherits the previous run's metadata automatically:

MetadataCarry-forward behavior
Search attributesFull merged map carries forward, including mid-run upserts
MemoFull merged map carries forward, including mid-run upserts
Visibility labelsCarried forward as-is (set once at start time)
Business keyCarried forward as-is
Compatibility markerCarried forward so the new run targets the same worker build
Message cursor positionCarried forward so the new run knows which inbound messages were already consumed through Message Streams

The new run starts with the inherited metadata and can continue upserting search attributes and memo from there. This means a long-lived polling workflow can accumulate metadata across generations without losing state when it sheds history.

use function Workflow\V2\{activity, continueAsNew, upsertMemo, upsertSearchAttributes};
use Workflow\V2\Workflow;

class PollingWorkflow extends Workflow
{
public function handle(int $iteration = 0)
{
$result = activity(PollActivity::class);

upsertSearchAttributes(['iteration' => (string) $iteration, 'status' => 'polling']);
upsertMemo(['last_result' => $result, 'iteration' => $iteration]);

if ($this->shouldContinueAsNew()) {
// The new run inherits all search attributes and memo
return continueAsNew($iteration + 1);
}

return ['result' => $result, 'iteration' => $iteration];
}
}

For long-lived human-input or assistant loops, prefer the first-class $this->inbox() / $this->outbox() Message Streams facade. Pending stream messages and cursor position move to the continued run, while consumed messages remain on the original run as history evidence.