Skip to content

REPL hot-reload for workers#88

Open
dotemacs wants to merge 2 commits into
manetu:masterfrom
metrictech:pr-repl-friendly
Open

REPL hot-reload for workers#88
dotemacs wants to merge 2 commits into
manetu:masterfrom
metrictech:pr-repl-friendly

Conversation

@dotemacs

@dotemacs dotemacs commented May 13, 2026

Copy link
Copy Markdown
Contributor

Two things that make REPLing a bit nicer

1. Silences the clojure.core/await warning

;; Before — every time you load temporal.workflow:
WARNING: await already refers to: #'clojure.core/await in namespace:
temporal.workflow, being replaced by: #'temporal.workflow/await

;; After — nothing. The core `await` isn't used anyway.

The SDK only ever uses its own temporal.workflow/await.

2. Hot reload, this is the real change in this PR

Adds two opt-in flags that store dispatch entries as Vars and deref them at execution time instead:

(worker/start client {:task-queue "my-queue"
                      :hot-reload-activities? true  ;; default false
                      :hot-reload-workflows?  true})

Re-evaluate a defactivity and the running worker picks it up immediately. Workflow hot reload is available too but marked as dev-only since workflow changes can mess with replay determinism.

Also closes #72

dotemacs added 2 commits May 13, 2026 13:15
Without this exclusion, this is the error that is shown every time
temporal.workflow is loaded:

WARNING: await already refers to: #'clojure.core/await in namespace:
temporal.workflow, being replaced by: #'temporal.workflow/await

Signed-off-by: Александар Симић <a@repl.ist>
Workers used to capture activity and workflow function values when
they started, which meant re-evaluating a definition at the REPL had
no effect until the worker was restarted.

Also requested here:
manetu#72

Add opt-in hot reload flags that keep dispatch entries linked to vars
and resolve them when work is executed. This lets activity changes,
and optionally workflow changes, be picked up by a running worker
during development.

Workflow hot reload remains explicit because workflow code changes can
affect replay determinism.

Signed-off-by: Александар Симић <a@repl.ist>

@thenonameguy thenonameguy left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Great, this will make my life much better. Thanks Alex :)

(let [d (u/find-dispatch dispatch workflow-type)
f (:fn d)
(let [d (u/resolve-dispatch ::def (u/find-dispatch dispatch workflow-type))
f (u/resolve-dispatch-fn d)

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.

IIUC, both resolve-dispatch and resolve-dispatch-fn do a (:var entry) decode. This seems like it could be a TOCTOU race, albeit I think a race with only mild implications. Would we be better off caching (:var) result and using it in both places?

(defn- -execute
[ctx dispatch args]
(let [{:keys [activity-type activity-id] :as _info} (get-info)
f (u/find-dispatch-fn dispatch activity-type)

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 think this s-exp is now unused, but it is left defined in the code. If there are no more users, please clean it up.

(format "%.3fx" (double x))
x))

(defn- report-criterium-comparison

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.

unused function

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.

Support defactivity/defworkflow var derefencing for hot-reloading code without worker restarts

3 participants