Skip to content

Conversation

@yuandrew
Copy link
Contributor

@yuandrew yuandrew commented Oct 29, 2025

What was changed

  • Plumb the ability to enable/disable worker heartbeating to TS lang layer
  • plumb plugin names to Core, to show in worker heartbeats
  • specify WorkerTaskTypes based on if workflows/activities/nexus handlers are registered to the worker
  • bumped sdk-core to 44a6576

Why?

New feature!

Checklist

  1. Closes [Feature Request] Enable Worker Heartbeating #1810

  2. How was this tested:

Manually tested that heartbeats with a simple plugin from the worker and client both show up in plugins section of the worker heartbeat.

Also tested setting workerHeartbeatInterval: null disables heartbeating for the worker

  1. Any docs updates needed?

Note

Adds configurable worker heartbeating, passes explicit task types and plugin names to Core, updates client/worker bridge APIs (incl. TLS/options), and bumps Core deps with minor error mapping tweaks.

  • Core bridge (Rust):
    • Runtime: Accepts worker_heartbeat_interval_millis and sets Core heartbeat_interval.
    • Worker: Maps new Core errors (WorkflowNotEnabled, ActivityNotEnabled, NexusNotEnabled) to UnexpectedError strings.
    • Worker Config: Replaces enable_non_local_activities with task_types and forwards plugins (as PluginInfo set).
    • Client: Switches to TlsOptions/ClientTlsOptions; uses new ClientOptions::builder() with maybe_* setters.
  • TypeScript bindings:
    • native.ts: RuntimeOptions gains workerHeartbeatIntervalMillis; WorkerOptions gains taskTypes and plugins; rename newRuntime param.
    • worker/runtime-options.ts: Adds workerHeartbeatInterval option; compiles to workerHeartbeatIntervalMillis.
    • worker/runtime.ts: Uses runtimeOptions instead of telemetryOptions when creating runtime and configuring metrics.
    • worker/worker-options.ts: Computes taskTypes from registered workflows/activities/nexus; forwards plugins.
  • Tests:
    • Update configs to include heartbeat interval, taskTypes, and plugins.
    • Add test verifying local activities work with non-local activities disabled.
  • Dependencies:
    • Cargo.lock updates (e.g., add bon, bump darling, update temporalio-client deps).

Written by Cursor Bugbot for commit 034eb3d. This will update automatically on new commits. Configure here.

@yuandrew yuandrew changed the title Enable Worker heartbeating Enable Worker heartbeating, plumb plugin names to core, update Core to 45b1d7e Nov 27, 2025
@yuandrew yuandrew marked this pull request as ready for review November 27, 2025 02:05
@yuandrew yuandrew requested a review from a team as a code owner November 27, 2025 02:05
Copy link
Member

@chris-olszewski chris-olszewski left a comment

Choose a reason for hiding this comment

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

Only required change is fixing up tests. Rest are light suggestions or questions.

}
}
CompleteWfError::WorkflowNotEnabled => {
BridgeError::UnexpectedError(format!("{err}"))
Copy link
Member

Choose a reason for hiding this comment

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

No strong opinions on this 🤷

Suggested change
BridgeError::UnexpectedError(format!("{err}"))
BridgeError::UnexpectedError(err.to_string())

.into_iter()
.map(|name| PluginInfo {
name,
version: String::new(),
Copy link
Member

Choose a reason for hiding this comment

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

Just for my own knowledge, is version from the past or not yet implemented?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good question, I don't know. haha. The API was originally implemented with version, but not sure what the intent was. Will follow up on this.

taskTypes: {
enableWorkflows,
enableLocalActivities,
enableRemoteActivities: opts.enableNonLocalActivities && opts.activities.size > 0,
Copy link
Contributor

Choose a reason for hiding this comment

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

That's basically saying:

enableRemoteActivities: (enableWorkflows && opts.activities.size > 0) && opts.activities.size > 0

Which is incorrect. We don't need workflows to enable remote activities. I'm surprised tests passed with this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think that's right, you're referring to enableLocalActivities, but I'm using opts.enableNonLocalActivities here

@yuandrew yuandrew requested a review from mjameswh December 4, 2025 00:55
max_activities_per_second: Option<f64>,
max_task_queue_activities_per_second: Option<f64>,
shutdown_grace_time: Option<Duration>,
plugins: Vec<String>,
Copy link
Member

@cretz cretz Dec 4, 2025

Choose a reason for hiding this comment

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

I think we should consider deduping plugins if we don't already. Depending on plugin implementation, it may be very normal to configure multiple of the same plugin on the same worker (maybe each has different settings).

This should be done in every SDK IMO too if we don't already (could consider making that Vec a Set on the Core side).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good point, a set would ensure deduping. Created temporalio/sdk-core#1072

const { metrics, noTemporalPrefixForMetrics } = options.telemetryOptions ?? {}; // eslint-disable-line deprecation/deprecation
const [logger, logExporter] = compileLoggerOptions(options);

const heartbeatMillis = msToNumber(options.workerHeartbeatInterval ?? '60s');
Copy link

Choose a reason for hiding this comment

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

Bug: Missing validation for heartbeat interval range

The documentation for workerHeartbeatInterval states "Accepted range is between 1s and 60s" but the implementation at line 378 doesn't validate this range. The code only checks if the value is 0 (to disable heartbeating) but accepts any other value without validation. Users could pass invalid values like 100ms or 2m which would be silently accepted, potentially causing unexpected behavior in worker heartbeating.

Additional Locations (1)

Fix in Cursor Fix in Web

Copy link
Contributor Author

Choose a reason for hiding this comment

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

enforced in core

@yuandrew yuandrew changed the title Enable Worker heartbeating, plumb plugin names to core, update Core to 45b1d7e Enable Worker heartbeating, plumb plugin names to core, update Core to 44a6576 Dec 9, 2025
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.

[Feature Request] Enable Worker Heartbeating

4 participants