dapr / dapr/js-sdk

getWorkflowState() stuck at RUNNING despite workflow completion (state sync bug)

Open
#734 2 comments 0 reactions 1 assignee Claimed by @WhitWaldo View on GitHub
area/workflow bug P0
Dominant language
JavaScript
Stars
217
Forks
104
PR merge metrics
No merged PRs in 30d

Description

# Dapr Workflow State Not Syncing After `whenAny` Resolution

## Expected Behavior

When a workflow completes after `whenAny([waitForExternalEvent, createTimer])` resolves, `getWorkflowState()` should return `COMPLETED` status within 1-2 seconds.

## Actual Behavior

The workflow completes internally (Dapr logs show `Orchestration completed with status COMPLETED`), but `getWorkflowState()` continues returning `RUNNING` indefinitely.

## Steps to Reproduce the Problem

1. Clone reproduction repository: [dapr-whenanybug-repro.zip](https://github.com/user-attachments/files/25282408/dapr-whenanybug-repro.zip)
```bash
cd dapr-whenanybug-repro
```

2. Deploy to Kubernetes cluster with Dapr installed:
```bash
# Build and load image
TAG="test-$(date +%Y%m%d-%H%M%S)"
docker build -t localhost:5001/dapr-whenanybug-integrated:${TAG} .
kind load docker-image localhost:5001/dapr-whenanybug-integrated:${TAG}

# Update deployment with image tag
sed -i "s|image: localhost:5001/dapr-whenanybug-integrated:.*|image: localhost:5001/dapr-whenanybug-integrated:${TAG}|" k8s/deployment.yaml

# Deploy
kubectl apply -f k8s/rbac.yaml
kubectl apply -f k8s/service.yaml
kubectl apply -f k8s/deployment.yaml
```

3. Watch the logs:
```bash
kubectl logs -f -l app=whenanybug-integrated -c integrated
```

4. Observe output:
- ✅ K8s job created by activity
- ✅ Job calls HTTP endpoint which raises event
- ✅ Workflow logs: `[Workflow] whenAny resolved!`
- ✅ Dapr logs: `Orchestration completed with status COMPLETED`
- ❌ Status check: `getWorkflowState()` returns `RUNNING` for 10+ seconds

## Environment

- **Dapr version:** 1.16.8
- **@dapr/dapr version:** 3.3.0
- **Kubernetes version:** 1.32
- **State store:** PostgreSQL with `actorStateStore: "true"`

## Code Pattern

```javascript
async function* jobWaitWorkflow(ctx, input) {
// Call activity to create K8s job
const result = yield ctx.callActivity('createJob', jobName);

// Wait for external event OR timeout
const eventTask = ctx.waitForExternalEvent(`job-done:${jobName}`);
const timerTask = ctx.createTimer(30);
const winner = yield ctx.whenAny([eventTask, timerTask]);

// BUG: Workflow completes here but state never syncs
return winner === eventTask ? 'completed' : 'timeout';
}
```

The K8s job calls back via HTTP, which raises the event using `client.raiseEvent()`. The workflow resolves internally but `client.getWorkflowState()` never reflects the completion.

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.