Skip to content

feat: add application-level keepalive to workflow runtime channel - #1795

Merged
siri-varma merged 4 commits into
dapr:masterfrom
javier-aliaga:grpc-keepalive-hello
Jul 30, 2026
Merged

feat: add application-level keepalive to workflow runtime channel#1795
siri-varma merged 4 commits into
dapr:masterfrom
javier-aliaga:grpc-keepalive-hello

Conversation

@javier-aliaga

Copy link
Copy Markdown
Contributor

Description

Adds an application-level keepalive to the workflow runtime's gRPC channel: while the runtime is started, the SDK pings the sidecar's hello RPC every 30s (5s deadline) on a daemon thread. Some L7 load balancers (e.g. AWS ALB) do not treat HTTP/2 PING frames as connection activity, so an idle getWorkItems stream gets killed at the idle timeout and workflow processing silently stops; a real RPC keeps the connection alive.

  • On by default, scoped to WorkflowRuntime.start()/close() — nothing pings before the runtime starts or after it closes.
  • Opt-out via dapr.workflows.runtime.app.keep.alive.enabled; interval tunable via dapr.workflows.app.keep.alive.interval.seconds.
  • Worker channel only: idle client connections just reconnect on the next call, so DaprWorkflowClient is untouched.
  • Failed pings are logged at debug to avoid log spam during sidecar outages.

Checklist

  • Code compiles correctly
  • Created/updated tests

JoshVanL and others added 4 commits July 29, 2026 11:00
…timeouts

AWS ALBs do not forward HTTP/2 PING frames, causing idle gRPC connections
to be closed. This adds a background loop that periodically calls the
existing Hello RPC as application-level traffic to keep the connection
alive through L7 load balancers.

Signed-off-by: joshvanl <me@joshvanl.dev>
Signed-off-by: joshvanl <me@joshvanl.dev>
… opt-in property

Relocate the hello() keepalive out of DurableTaskGrpcWorker (reverted to
master) into sdk-workflows, per review feedback: the keepalive is a channel
concern, so it now lives with the classes that create workflow channels.

- New internal GrpcChannelKeepalive: pings hello() on a daemon thread,
  catches Throwable so a ping failure can never cancel the periodic task,
  applies the 5s deadline per ping.
- WorkflowRuntimeBuilder creates it on the worker channel; WorkflowRuntime
  owns and closes it (new optional constructor arg).
- DaprWorkflowClient wires it on the client channel, protecting long
  waitForInstanceCompletion calls through L7 load balancers too.
- Gated behind dapr.workflows.app.keep.alive.enabled (default false) with
  dapr.workflows.app.keep.alive.interval.seconds (default 30), following
  the existing opt-in convention of dapr.grpc.enable.keep.alive.
- Tests: in-process gRPC server coverage for ping cadence, failure
  tolerance, and close semantics; gating tests for both channel owners.

Signed-off-by: Javier Aliaga <javier@diagrid.io>
Restore fix-by-default for the worker channel: the keepalive now defaults
to on, but only pings between WorkflowRuntime.start() and close() - a
started runtime is by definition talking to a sidecar, so idle apps and
built-but-unstarted runtimes send nothing.

- GrpcChannelKeepalive lifecycle is explicit: inert constructor,
  idempotent start() and close().
- dapr.workflows.app.keep.alive.enabled (opt-in) is replaced by
  dapr.workflows.runtime.app.keep.alive.enabled (default true, opt-out).
- Drop the client-channel keepalive: a dead idle client connection
  reconnects on the next call, so it isn't worth the extra surface;
  DaprWorkflowClient reverts to master.

Signed-off-by: Javier Aliaga <javier@diagrid.io>
@javier-aliaga
javier-aliaga requested review from a team as code owners July 30, 2026 09:05
@codecov

codecov Bot commented Jul 30, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.61905% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 77.10%. Comparing base (82df6f9) to head (811eee7).
⚠️ Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
...dapr/workflows/runtime/WorkflowRuntimeBuilder.java 80.00% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##             master    #1795      +/-   ##
============================================
+ Coverage     76.85%   77.10%   +0.25%     
- Complexity     2300     2317      +17     
============================================
  Files           244      245       +1     
  Lines          7145     7186      +41     
  Branches        748      750       +2     
============================================
+ Hits           5491     5541      +50     
+ Misses         1288     1284       -4     
+ Partials        366      361       -5     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@siri-varma
siri-varma merged commit 2edf16c into dapr:master Jul 30, 2026
11 checks passed
@javier-aliaga
javier-aliaga deleted the grpc-keepalive-hello branch July 31, 2026 06:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants