Skip to content

Enable workflow restoration for WAITING status#1246

Draft
mcruzdev wants to merge 1 commit intoserverlessworkflow:mainfrom
mcruzdev:issue-1245
Draft

Enable workflow restoration for WAITING status#1246
mcruzdev wants to merge 1 commit intoserverlessworkflow:mainfrom
mcruzdev:issue-1245

Conversation

@mcruzdev
Copy link
Collaborator

@mcruzdev mcruzdev commented Mar 20, 2026

This pull request introduces support for handling workflow status changes, specifically persisting the WAITING status, in the workflow persistence layer. It does so by extending the persistence writer and listener interfaces and implementations to handle status change events. The most important changes are grouped below:

Persistence API Enhancements:

  • Added a new statusChanged method to the PersistenceInstanceWriter interface, allowing the persistence layer to handle workflow status updates.
  • Implemented the statusChanged method in AbstractPersistenceInstanceWriter, which writes the new status using a transaction.

Workflow Status Handling:

  • Updated WorkflowPersistenceListener to listen for WorkflowStatusEvent and persist the WAITING status via the new statusChanged method. [1] [2]
  • Modified WorkflowPersistenceInstance to explicitly persist the WAITING status when starting a workflow, ensuring the status is accurately reflected.

@mcruzdev mcruzdev requested a review from fjtirado as a code owner March 20, 2026 02:08
Copilot AI review requested due to automatic review settings March 20, 2026 02:08
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Enables persisted workflows that are in WAITING (e.g., blocked on listen()/wait) to restore correctly after a restart by persisting WAITING status changes and ensuring restored instances re-enter WAITING rather than being treated like SUSPENDED.

Changes:

  • Persist workflow WAITING transitions via a new PersistenceInstanceWriter.statusChanged(...) hook.
  • Restore persisted WAITING workflows by setting instance status to WAITING on start().
  • Add a default statusChanged(...) implementation in the abstract writer to write the persisted status.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
impl/persistence/api/src/main/java/io/serverlessworkflow/impl/persistence/WorkflowPersistenceListener.java Persists WAITING status transitions on lifecycle status-change events.
impl/persistence/api/src/main/java/io/serverlessworkflow/impl/persistence/WorkflowPersistenceInstance.java On restore/start, sets restored instances to WAITING when persisted status is WAITING.
impl/persistence/api/src/main/java/io/serverlessworkflow/impl/persistence/PersistenceInstanceWriter.java Extends persistence writer API with statusChanged(...).
impl/persistence/api/src/main/java/io/serverlessworkflow/impl/persistence/AbstractPersistenceInstanceWriter.java Implements statusChanged(...) by writing status in a transaction.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +86 to 91
if (ev.status() == WorkflowStatus.WAITING) {
// Only persist WAITING for now
persistenceWriter.statusChanged(ev.workflowContext(), ev.status());
}
}
}
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Persisting WAITING on entry without also clearing/updating the persisted status when the workflow leaves WAITING can leave a stale WAITING status in persistence (e.g., when the workflow transitions WAITING -> RUNNING after an event arrives). This can make restored instances and operational queries report incorrect state. Consider also handling status changes away from WAITING (e.g., if previousStatus == WAITING and new status != WAITING then clear the persisted status, or persist all status changes).

Suggested change
if (ev.status() == WorkflowStatus.WAITING) {
// Only persist WAITING for now
persistenceWriter.statusChanged(ev.workflowContext(), ev.status());
}
}
}
// Persist all status changes so a previously persisted WAITING status
// is overwritten when the workflow leaves WAITING.
persistenceWriter.statusChanged(ev.workflowContext(), ev.status());
}
}

Copilot uses AI. Check for mistakes.
Comment on lines 38 to 46
public CompletableFuture<WorkflowModel> start() {
return startExecution(
() -> {
if (info.status() == WorkflowStatus.SUSPENDED) {
internalSuspend();
} else if (info.status() == WorkflowStatus.WAITING) {
status(WorkflowStatus.WAITING);
}
});
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR’s behavior change is meant to ensure restored WAITING workflows re-register event listeners and can resume after restart, but there doesn’t appear to be a test that simulates: persist a workflow while WAITING -> restart application/load from persistence -> publish the awaited CloudEvent -> assert the workflow resumes/completes. Adding an integration test using the existing InMemoryEvents broker + persistence handlers would guard against regressions.

Copilot uses AI. Check for mistakes.
Workflows in WAITING status now properly restore after restart by re-registering
event listeners. Modified WorkflowPersistenceInstance to skip internalSuspend()
for WAITING status, allowing listen tasks to re-execute and register handlers.

Signed-off-by: Matheus Cruz <matheuscruz.dev@gmail.com>
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@Override
public CompletableFuture<Void> statusChanged(
WorkflowContextData workflowContext, WorkflowStatus status) {
return doTransaction(t -> t.writeStatus(workflowContext, status), workflowContext);
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new statusChanged implementation is a bit harder to read than the surrounding methods due to being on a single long line. Consider wrapping the doTransaction(...) call in the same style as suspended(...)/taskCompleted(...) to keep formatting consistent and improve readability.

Suggested change
return doTransaction(t -> t.writeStatus(workflowContext, status), workflowContext);
return doTransaction(
t -> t.writeStatus(workflowContext, status), workflowContext);

Copilot uses AI. Check for mistakes.
@fjtirado fjtirado marked this pull request as draft March 20, 2026 11:04
@fjtirado
Copy link
Collaborator

I do not see the need for this one.
When a workflow is restored, it will naturally reach the waiting state (or any other state) based on the list of already completed task.
The only status that needs to be stored is the suspend one, because that one is not reached naturally, it is decided by the user

@fjtirado
Copy link
Collaborator

What needs to be debugged is why, when after restore, ListerExecutor is called, the re-registration does not occur, but that wont be fixed with this change

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants