mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-24 16:54:43 +00:00
fix(cron): scope hermes_home override per-profile in multiplex ticker
The multiplex cron path only used use_cron_store() to scope storage paths (jobs.json, heartbeat files), but _get_lock_paths() and the agent execution path in cron/scheduler.py resolve via _get_hermes_home() → get_hermes_home() which checks _HERMES_HOME_OVERRIDE, a separate ContextVar. Without set_hermes_home_override(), the .tick.lock, config.yaml, .env, and secrets all resolved to the default profile instead of the per-profile home. This matches the web_server.py pattern (line 11994) which sets both set_hermes_home_override(home) AND use_cron_store(home), and the _profile_runtime_scope pattern used for the multiplexed inbound path. Found via 3-agent parallel review of salvaged PR #69529.
This commit is contained in:
parent
6c98eb2d45
commit
a61183b56f
1 changed files with 37 additions and 22 deletions
|
|
@ -259,13 +259,16 @@ class InProcessCronScheduler(CronScheduler):
|
|||
):
|
||||
"""Tick every served profile's cron store when multiplex_profiles is on.
|
||||
|
||||
Each profile uses ``use_cron_store()`` to scope its tick, heartbeat,
|
||||
and recovery to that profile's own ``cron/jobs.json`` — mirroring how
|
||||
the multiplexer already scopes config/SOUL/memory per turn.
|
||||
Each profile uses ``set_hermes_home_override()`` + ``use_cron_store()``
|
||||
to scope its tick, heartbeat, recovery, lock file, config/.env, and
|
||||
agent execution to that profile's home — mirroring how
|
||||
``_profile_runtime_scope`` scopes the multiplexed inbound path and
|
||||
``web_server.py`` scopes per-profile cron API calls.
|
||||
"""
|
||||
import logging
|
||||
from cron.scheduler import tick as cron_tick
|
||||
from cron.jobs import record_ticker_heartbeat, use_cron_store
|
||||
from hermes_constants import set_hermes_home_override, reset_hermes_home_override
|
||||
|
||||
logger = logging.getLogger("cron.scheduler_provider")
|
||||
logger.info(
|
||||
|
|
@ -277,15 +280,19 @@ class InProcessCronScheduler(CronScheduler):
|
|||
# Recovery + initial heartbeat for every profile.
|
||||
for entry in profile_homes:
|
||||
home = entry[1] if isinstance(entry, tuple) else entry
|
||||
with use_cron_store(home):
|
||||
recovered = self.recover_interrupted()
|
||||
if recovered:
|
||||
logger.warning(
|
||||
"Marked %d interrupted cron execution(s) for profile at %s",
|
||||
recovered,
|
||||
home,
|
||||
)
|
||||
record_ticker_heartbeat()
|
||||
home_token = set_hermes_home_override(str(home))
|
||||
try:
|
||||
with use_cron_store(home):
|
||||
recovered = self.recover_interrupted()
|
||||
if recovered:
|
||||
logger.warning(
|
||||
"Marked %d interrupted cron execution(s) for profile at %s",
|
||||
recovered,
|
||||
home,
|
||||
)
|
||||
record_ticker_heartbeat()
|
||||
finally:
|
||||
reset_hermes_home_override(home_token)
|
||||
|
||||
while not stop_event.is_set():
|
||||
ok = False
|
||||
|
|
@ -295,20 +302,28 @@ class InProcessCronScheduler(CronScheduler):
|
|||
else:
|
||||
for entry in profile_homes:
|
||||
home = entry[1] if isinstance(entry, tuple) else entry
|
||||
with use_cron_store(home):
|
||||
cron_tick(
|
||||
verbose=False,
|
||||
adapters=adapters,
|
||||
loop=loop,
|
||||
sync=False,
|
||||
can_dispatch=can_dispatch,
|
||||
)
|
||||
home_token = set_hermes_home_override(str(home))
|
||||
try:
|
||||
with use_cron_store(home):
|
||||
cron_tick(
|
||||
verbose=False,
|
||||
adapters=adapters,
|
||||
loop=loop,
|
||||
sync=False,
|
||||
can_dispatch=can_dispatch,
|
||||
)
|
||||
finally:
|
||||
reset_hermes_home_override(home_token)
|
||||
ok = True
|
||||
except BaseException as e:
|
||||
logger.error("Cron tick error: %s", e, exc_info=True)
|
||||
# Record per-profile heartbeat after each tick cycle.
|
||||
for entry in profile_homes:
|
||||
home = entry[1] if isinstance(entry, tuple) else entry
|
||||
with use_cron_store(home):
|
||||
record_ticker_heartbeat(success=ok)
|
||||
home_token = set_hermes_home_override(str(home))
|
||||
try:
|
||||
with use_cron_store(home):
|
||||
record_ticker_heartbeat(success=ok)
|
||||
finally:
|
||||
reset_hermes_home_override(home_token)
|
||||
stop_event.wait(interval)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue