Skip to content

feat: add health endpoints - #590

Draft
JeffreyJPZ wants to merge 52 commits into
dapr:mainfrom
JeffreyJPZ:health-endpoints
Draft

feat: add health endpoints#590
JeffreyJPZ wants to merge 52 commits into
dapr:mainfrom
JeffreyJPZ:health-endpoints

Conversation

@JeffreyJPZ

@JeffreyJPZ JeffreyJPZ commented Apr 29, 2026

Copy link
Copy Markdown
Contributor

Description

Changes

  • Exposes /livez and /readyz endpoints when agents are hosted as a service.
  • Refactors runtime config updates and agent config resolution so that they use the same coerce/validate/transform/apply logic.
  • Creates a agent execution ToolChoice enum for consistency.
  • Move config resolution logic from the agent to the config classes.
  • Extracts agent execution defaults to named constants.

Issue reference

We strive to have all PR being opened based on an issue, where the problem or feature have been discussed prior to implementation.

Please reference the issue this PR closes: #375

Checklist

Please make sure you've completed the relevant tasks for this PR, out of the following list:

  • Created/updated tests
  • Tested this change against all the quickstarts
  • Extended the documentation

Note: We expect contributors to open a corresponding documentation PR in the dapr/docs repository. As the implementer, you are the best person to document your work! Implementation PRs will not be merged until the documentation PR is opened and ready for review.

TODO:

  • Update docs
  • Update 03-message-router-workflow example

Signed-off-by: Jeffrey Zhang <jeffreyjpizhang@gmail.com>
Signed-off-by: Jeffrey Zhang <jeffreyjpizhang@gmail.com>
Signed-off-by: Jeffrey Zhang <jeffreyjpizhang@gmail.com>
@JeffreyJPZ
JeffreyJPZ requested a review from a team as a code owner April 29, 2026 05:22
Copilot AI review requested due to automatic review settings April 29, 2026 05:22
@JeffreyJPZ
JeffreyJPZ requested a review from a team as a code owner April 29, 2026 05:22

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds service health endpoints for hosted agents and introduces a readiness signal path from pub/sub consumer subscriptions up to the agent runner.

Changes:

  • Add /livez and /readyz endpoints to AgentRunner.serve() and implement readiness logic based on runner/agent wiring state.
  • Extend pub/sub subscription registration to return per-consumer “ready” status functions (in addition to closers), and thread this through runners.
  • Add/adjust tests to validate route registration return values and health endpoint behavior.

Reviewed changes

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

Show a summary per file
File Description
dapr_agents/workflow/runners/agent.py Mounts health/readiness endpoints and checks readiness conditions.
dapr_agents/workflow/runners/base.py Stores/clears pubsub consumer status functions alongside closers.
dapr_agents/workflow/utils/registration.py Changes route registration APIs to return (closers, status_functions).
dapr_agents/workflow/utils/subscription.py Builds status functions per streaming subscription and returns them with closers.
tests/workflow/test_message_router.py Updates tests for new (closers, status_functions) return shape.
tests/workflow/test_agent_runner.py Adds tests covering /livez and /readyz behavior under different states.

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

Comment thread dapr_agents/workflow/runners/agent.py
Comment thread tests/workflow/test_agent_runner.py Outdated
Comment thread dapr_agents/workflow/utils/subscription.py
Comment thread dapr_agents/workflow/utils/subscription.py Outdated
Comment thread dapr_agents/workflow/runners/agent.py
Comment thread dapr_agents/workflow/runners/agent.py Outdated
Comment thread dapr_agents/workflow/runners/agent.py Outdated
entry_path: str = "/agent/run",
status_path: str = "/agent/instances/{instance_id}",
health_check_path: str = "/livez",
readiness_check_path: str = "/readyz",

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Should Dapr Agent app health endpoints point to /readyz rather than /livez since it better aligns with Dapr health checks goals (i.e. "can it accept traffic?")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You've done the right thing here. In k8s lingo it's /readyz and /livez. We should update the default dapr to deprecate /healtz. Keep as-is in this pr :-)

@JeffreyJPZ JeffreyJPZ May 2, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Since both app health checks and K8s health checks are opt-in, should there also be a flag to determine if these endpoints should be exposed (similar to expose_entry)?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yes that would be great. If you can add both an ENV variable + a setting in the agent execution config.
You can see the agent observability config. We should let the priority be agent execution config > env variable > default

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

If i'm not misunderstanding something, most CLI flags/K8s annotations aren't automatically made available as env variables in the app? Should we expect the env variable names to follow the CLI flags/K8s annotations (e.g. ENABLE_APP_HEALTH_CHECK, APP_HEALTH_CHECK_PATH)?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'd go with ENABLE_APP_HEALTH_CHECK and ENABLE_APP_READY_CHECK.
You are correct that CLI flags and annotations aren't available as env vars.
In the real deployment model you'd either serve them as env vars on the manifest or you'd mount a configmap as env vars with the details.

We shouldn't let the path be overwritten imo.

When running locally you can just run export ENABLE_APP_HEALTH_CHECK in the terminal for it to be available as env var.

Comment thread dapr_agents/workflow/runners/agent.py
Comment thread dapr_agents/workflow/utils/registration.py
Comment thread dapr_agents/workflow/utils/subscription.py Outdated
CasperGN and others added 2 commits May 1, 2026 10:28
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Casper Nielsen <whopsec@protonmail.com>
@CasperGN

CasperGN commented May 1, 2026

Copy link
Copy Markdown
Contributor

@JeffreyJPZ thank you for this one!

Can you move your comments to address the copilot review as it's a little confusing to me which belongs where?

JeffreyJPZ added 4 commits May 1, 2026 12:03
Signed-off-by: Jeffrey Zhang <jeffreyjpizhang@gmail.com>
Signed-off-by: Jeffrey Zhang <jeffreyjpizhang@gmail.com>
Signed-off-by: Jeffrey Zhang <jeffreyjpizhang@gmail.com>
Signed-off-by: Jeffrey Zhang <jeffreyjpizhang@gmail.com>

@CasperGN CasperGN left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

A few comments for changes

Comment thread dapr_agents/workflow/runners/agent.py Outdated
self._default_http_paths.add(health_check_path)

async def _get_health_status() -> dict[str, str]:
return {"status": "ok"}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

As done with the _is_ready() func, can we also include a check for the health endpoint so we know that the agent is actually running healthy?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Would this be the same as _is_ready excluding checking pub/sub consumers and HTTP routes (and shutdown signals)?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hm. I think I was more referring to checking the internals of the agent. The agent could in theory be stuck in a workflow or throwing unrecoverable errors while this would still return ok

@JeffreyJPZ JeffreyJPZ May 5, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thats fair. My initial thoughts are on some sort of heartbeat mechanism/watcher thread. I'm also looking at the unrecoverable error path in the subscription code, it looks like the consumer thread just logs the error and exits? Should there be self-healing by recreating consumer threads, or should it just report unhealthy and have K8s restart the container?

Some questions building off of my initial thoughts:

  • What if the watcher thread goes down? Can it be reactivated somehow (maybe reminders?)
  • How can one distinguish between a really long workflow and a "stuck" workflow, if that even is possible? AFAIK there's no "global" timeout for workflows (which I guess would defeat the point of a workflow), but maybe this can be configured on the agent somehow?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Regarding the subscription, I think it's fine to report unhealthy and restart. We gotta be careful not to interfere with the expected behavior of retries etc as that comes from the retry policies.

@JoshVanL do you have some input here about how we could probe the wf runtime to infer if it's "running healthy" or not?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Looks like there's only the wait_for_worker_ready method, but that's probably not enough

Comment thread dapr_agents/workflow/runners/agent.py Outdated
Comment thread dapr_agents/workflow/runners/agent.py Outdated
entry_path: str = "/agent/run",
status_path: str = "/agent/instances/{instance_id}",
health_check_path: str = "/livez",
readiness_check_path: str = "/readyz",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yes that would be great. If you can add both an ENV variable + a setting in the agent execution config.
You can see the agent observability config. We should let the priority be agent execution config > env variable > default

Comment thread dapr_agents/workflow/runners/agent.py Outdated
Comment thread dapr_agents/workflow/utils/subscription.py
@CasperGN CasperGN self-assigned this May 4, 2026
JeffreyJPZ added 4 commits May 4, 2026 16:43
Signed-off-by: Jeffrey Zhang <jeffreyjpizhang@gmail.com>
Signed-off-by: Jeffrey Zhang <jeffreyjpizhang@gmail.com>
Signed-off-by: Jeffrey Zhang <jeffreyjpizhang@gmail.com>
Signed-off-by: Jeffrey Zhang <jeffreyjpizhang@gmail.com>
Comment thread dapr_agents/workflow/utils/registration.py
Comment thread dapr_agents/workflow/utils/registration.py Outdated
Comment thread dapr_agents/workflow/utils/subscription.py Outdated
Comment thread dapr_agents/workflow/runners/agent.py Outdated
JeffreyJPZ and others added 4 commits May 5, 2026 17:04
Signed-off-by: Jeffrey Zhang <jeffreyjpizhang@gmail.com>
Signed-off-by: Jeffrey Zhang <jeffreyjpizhang@gmail.com>
Signed-off-by: Jeffrey Zhang <jeffreyjpizhang@gmail.com>
Signed-off-by: Jeffrey Zhang <jeffreyjpizhang@gmail.com>
Signed-off-by: Jeffrey Zhang <jeffreyjpizhang@gmail.com>
Signed-off-by: Jeffrey Zhang <jeffreyjpizhang@gmail.com>
Signed-off-by: Jeffrey Zhang <jeffreyjpizhang@gmail.com>
Signed-off-by: Jeffrey Zhang <jeffreyjpizhang@gmail.com>
Comment thread mypy.ini

[mypy]
python_version = 3.10
python_version = 3.11

@JeffreyJPZ JeffreyJPZ May 16, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Needed to bump the version since StrEnum is only supported in >=3.11, and some tests rely on str(enum) being equal to the string value which only works in >=3.11. I think it was stale anyway since the pyproject file specifies >=3.11.

sicoyle and others added 5 commits May 18, 2026 10:23
Signed-off-by: Jeffrey Zhang <jeffreyjpizhang@gmail.com>
Signed-off-by: Jeffrey Zhang <jeffreyjpizhang@gmail.com>
Signed-off-by: Jeffrey Zhang <jeffreyjpizhang@gmail.com>
Comment on lines +877 to +880
except RuntimeError as e:
# Fall through if the agent could not be updated but the value is otherwise valid
logger.debug(f"Agent {self.name}: {e}")
applied_value = None

@JeffreyJPZ JeffreyJPZ May 19, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Was this behaviour intended from the beginning? Had to split the config update in two which leads to a bit of redundant processing because of this, not sure if there's another way.

JeffreyJPZ added 11 commits May 19, 2026 16:49
Signed-off-by: Jeffrey Zhang <jeffreyjpizhang@gmail.com>
Signed-off-by: Jeffrey Zhang <jeffreyjpizhang@gmail.com>
Signed-off-by: Jeffrey Zhang <jeffreyjpizhang@gmail.com>
Signed-off-by: Jeffrey Zhang <jeffreyjpizhang@gmail.com>
Signed-off-by: Jeffrey Zhang <jeffreyjpizhang@gmail.com>
Signed-off-by: Jeffrey Zhang <jeffreyjpizhang@gmail.com>
Signed-off-by: Jeffrey Zhang <jeffreyjpizhang@gmail.com>
Signed-off-by: Jeffrey Zhang <jeffreyjpizhang@gmail.com>
Signed-off-by: Jeffrey Zhang <jeffreyjpizhang@gmail.com>
Signed-off-by: Jeffrey Zhang <jeffreyjpizhang@gmail.com>
Signed-off-by: Jeffrey Zhang <jeffreyjpizhang@gmail.com>
@JeffreyJPZ
JeffreyJPZ marked this pull request as draft May 21, 2026 22:24
@github-actions

Copy link
Copy Markdown

This pull request has been automatically marked as stale because it has not had activity in the last 60 days. It will be closed in 7 days if no further activity occurs. Please feel free to give a status update now, ping for review, or re-open when it's ready. Thank you for your contributions!

@github-actions github-actions Bot added the stale label Jul 20, 2026
@JeffreyJPZ

Copy link
Copy Markdown
Contributor Author

keep-alive

@github-actions github-actions Bot removed the stale label Jul 20, 2026
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.

Add health endpoints to Dapr Agent for Kubernetes and Dapr probes

5 participants