refactor(cron): AST-neutral bracket packing
This commit is contained in:
@@ -719,9 +719,7 @@ def _resolve_schedule(blueprint: AutomationBlueprint, values: Dict[str, Any]) ->
|
|||||||
|
|
||||||
|
|
||||||
def fill_blueprint(
|
def fill_blueprint(
|
||||||
blueprint: AutomationBlueprint,
|
blueprint: AutomationBlueprint, values: Dict[str, Any], *,
|
||||||
values: Dict[str, Any],
|
|
||||||
*,
|
|
||||||
origin: Optional[Dict[str, Any]] = None,
|
origin: Optional[Dict[str, Any]] = None,
|
||||||
) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
"""Validate ``values`` and return ``cron.jobs.create_job`` kwargs.
|
"""Validate ``values`` and return ``cron.jobs.create_job`` kwargs.
|
||||||
|
|||||||
+2
-4
@@ -50,8 +50,7 @@ def prepare_ledger(conn: sqlite3.Connection, *, db_label: str, synchronous_full:
|
|||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def ledger_transaction(
|
def ledger_transaction(
|
||||||
lock: threading.RLock,
|
lock: threading.RLock, connect: Callable[[], sqlite3.Connection],
|
||||||
connect: Callable[[], sqlite3.Connection],
|
|
||||||
initialize_schema: Callable[[sqlite3.Connection], None],
|
initialize_schema: Callable[[sqlite3.Connection], None],
|
||||||
) -> Iterator[sqlite3.Connection]:
|
) -> Iterator[sqlite3.Connection]:
|
||||||
"""Open a connection, commit/rollback on exit, always close. ``sqlite3.Connection``'s own context
|
"""Open a connection, commit/rollback on exit, always close. ``sqlite3.Connection``'s own context
|
||||||
@@ -249,8 +248,7 @@ def recover_interrupted_executions() -> int:
|
|||||||
|
|
||||||
|
|
||||||
def list_executions(
|
def list_executions(
|
||||||
*, job_id: Optional[str] = None, limit: int = 50,
|
*, job_id: Optional[str] = None, limit: int = 50, before_claimed_at: Optional[str] = None,
|
||||||
before_claimed_at: Optional[str] = None,
|
|
||||||
) -> List[Dict[str, Any]]:
|
) -> List[Dict[str, Any]]:
|
||||||
"""Return indexed, newest-first execution history with cursor pagination."""
|
"""Return indexed, newest-first execution history with cursor pagination."""
|
||||||
clauses: List[str] = []
|
clauses: List[str] = []
|
||||||
|
|||||||
+1
-5
@@ -137,11 +137,7 @@ def _classify_failure_type(error: str) -> str:
|
|||||||
|
|
||||||
|
|
||||||
def upsert_incident(
|
def upsert_incident(
|
||||||
job_id: str,
|
job_id: str, error: str, *, job_name: Optional[str] = None, failure_type: Optional[str] = None,
|
||||||
error: str,
|
|
||||||
*,
|
|
||||||
job_name: Optional[str] = None,
|
|
||||||
failure_type: Optional[str] = None,
|
|
||||||
output_file: Optional[str] = None,
|
output_file: Optional[str] = None,
|
||||||
) -> tuple[str, bool]:
|
) -> tuple[str, bool]:
|
||||||
"""Record (or refresh) the incident for ``job_id`` + ``error``; returns ``(incident_id, is_new)``.
|
"""Record (or refresh) the incident for ``job_id`` + ``error``; returns ``(incident_id, is_new)``.
|
||||||
|
|||||||
@@ -688,11 +688,7 @@ def _read_script_for_scanning(script_path: str) -> str:
|
|||||||
# --- recursive walk ---------------------------------------------------------------------------
|
# --- recursive walk ---------------------------------------------------------------------------
|
||||||
|
|
||||||
def _contains_unsafe_gateway_action(
|
def _contains_unsafe_gateway_action(
|
||||||
command: str,
|
command: str, *, cwd: Optional[str], depth: int, visited: set[Path],
|
||||||
*,
|
|
||||||
cwd: Optional[str],
|
|
||||||
depth: int,
|
|
||||||
visited: set[Path],
|
|
||||||
read_remote_script: Optional[_ReadRemoteScriptFn] = None,
|
read_remote_script: Optional[_ReadRemoteScriptFn] = None,
|
||||||
) -> bool:
|
) -> bool:
|
||||||
if _direct_lifecycle_scan(command):
|
if _direct_lifecycle_scan(command):
|
||||||
@@ -735,9 +731,7 @@ def _contains_unsafe_gateway_action(
|
|||||||
|
|
||||||
|
|
||||||
def contains_gateway_lifecycle_command_or_referenced_script(
|
def contains_gateway_lifecycle_command_or_referenced_script(
|
||||||
command: str,
|
command: str, *, cwd: Optional[str] = None,
|
||||||
*,
|
|
||||||
cwd: Optional[str] = None,
|
|
||||||
read_remote_script: Optional[_ReadRemoteScriptFn] = None,
|
read_remote_script: Optional[_ReadRemoteScriptFn] = None,
|
||||||
) -> bool:
|
) -> bool:
|
||||||
"""Detect lifecycle/submit commands, including bounded nested scripts.
|
"""Detect lifecycle/submit commands, including bounded nested scripts.
|
||||||
|
|||||||
+1
-5
@@ -49,11 +49,7 @@ def build_monitor_diff(old: str, new: str) -> str:
|
|||||||
"""Unified diff of old vs new monitor output, capped at MAX_DIFF_CHARS."""
|
"""Unified diff of old vs new monitor output, capped at MAX_DIFF_CHARS."""
|
||||||
diff = "\n".join(
|
diff = "\n".join(
|
||||||
difflib.unified_diff(
|
difflib.unified_diff(
|
||||||
old.splitlines(),
|
old.splitlines(), new.splitlines(), fromfile="previous", tofile="current", lineterm="",
|
||||||
new.splitlines(),
|
|
||||||
fromfile="previous",
|
|
||||||
tofile="current",
|
|
||||||
lineterm="",
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if len(diff) > MAX_DIFF_CHARS:
|
if len(diff) > MAX_DIFF_CHARS:
|
||||||
|
|||||||
+17
-66
@@ -78,11 +78,7 @@ class CronScheduler(ABC):
|
|||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def start(
|
def start(
|
||||||
self,
|
self, stop_event: threading.Event, *, adapters: Any = None, loop: Any = None,
|
||||||
stop_event: threading.Event,
|
|
||||||
*,
|
|
||||||
adapters: Any = None,
|
|
||||||
loop: Any = None,
|
|
||||||
interval: int = 60,
|
interval: int = 60,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Begin firing due jobs. Built-in BLOCKS until stop_event is set (run in a daemon thread);
|
"""Begin firing due jobs. Built-in BLOCKS until stop_event is set (run in a daemon thread);
|
||||||
@@ -115,12 +111,7 @@ class CronScheduler(ABC):
|
|||||||
return provider_supports_force_fire(self)
|
return provider_supports_force_fire(self)
|
||||||
|
|
||||||
def fire_due(
|
def fire_due(
|
||||||
self,
|
self, job_id: str, *, adapters: Any = None, loop: Any = None, force: bool = False,
|
||||||
job_id: str,
|
|
||||||
*,
|
|
||||||
adapters: Any = None,
|
|
||||||
loop: Any = None,
|
|
||||||
force: bool = False,
|
|
||||||
) -> bool:
|
) -> bool:
|
||||||
"""Run one job NOW (inbound fire webhook entry). Store CAS claim (multi-machine
|
"""Run one job NOW (inbound fire webhook entry). Store CAS claim (multi-machine
|
||||||
at-most-once) then shared ``run_one_job``. True if THIS caller claimed and processed the
|
at-most-once) then shared ``run_one_job``. True if THIS caller claimed and processed the
|
||||||
@@ -144,8 +135,7 @@ class CronScheduler(ABC):
|
|||||||
claimed_job = claim_job_for_fire(job_id, **claim_kwargs)
|
claimed_job = claim_job_for_fire(job_id, **claim_kwargs)
|
||||||
except BaseException as exc:
|
except BaseException as exc:
|
||||||
finish_execution(
|
finish_execution(
|
||||||
execution["id"],
|
execution["id"], success=False,
|
||||||
success=False,
|
|
||||||
error=f"Fire claim failed before dispatch: {type(exc).__name__}: {exc}",
|
error=f"Fire claim failed before dispatch: {type(exc).__name__}: {exc}",
|
||||||
)
|
)
|
||||||
raise
|
raise
|
||||||
@@ -156,11 +146,7 @@ class CronScheduler(ABC):
|
|||||||
return claimed_job
|
return claimed_job
|
||||||
|
|
||||||
def fire_claimed(
|
def fire_claimed(
|
||||||
self,
|
self, claimed_job: dict, *, adapters: Any = None, loop: Any = None,
|
||||||
claimed_job: dict,
|
|
||||||
*,
|
|
||||||
adapters: Any = None,
|
|
||||||
loop: Any = None,
|
|
||||||
cancel_event: Any = None,
|
cancel_event: Any = None,
|
||||||
) -> bool:
|
) -> bool:
|
||||||
"""Run an exact ``claim_fire`` snapshot; ``cancel_event`` lets the transport stop it
|
"""Run an exact ``claim_fire`` snapshot; ``cancel_event`` lets the transport stop it
|
||||||
@@ -220,11 +206,7 @@ def _misfire_grace_minutes() -> float:
|
|||||||
|
|
||||||
|
|
||||||
def fire_overdue_jobs(
|
def fire_overdue_jobs(
|
||||||
provider: "CronScheduler",
|
provider: "CronScheduler", *, adapters: Any = None, loop: Any = None, now: Any = None,
|
||||||
*,
|
|
||||||
adapters: Any = None,
|
|
||||||
loop: Any = None,
|
|
||||||
now: Any = None,
|
|
||||||
) -> int:
|
) -> int:
|
||||||
"""Misfire backstop (gateway housekeeping loop): fire jobs whose external HTTP fire never
|
"""Misfire backstop (gateway housekeeping loop): fire jobs whose external HTTP fire never
|
||||||
arrived, else ``next_run_at`` stays parked in the past forever. No-op for the built-in (its tick
|
arrived, else ``next_run_at`` stays parked in the past forever. No-op for the built-in (its tick
|
||||||
@@ -289,10 +271,8 @@ def fire_overdue_jobs(
|
|||||||
if claimed is None:
|
if claimed is None:
|
||||||
continue
|
continue
|
||||||
threading.Thread(
|
threading.Thread(
|
||||||
target=provider.fire_claimed,
|
target=provider.fire_claimed, args=(claimed,),
|
||||||
args=(claimed,),
|
kwargs={"adapters": adapters, "loop": loop}, daemon=True,
|
||||||
kwargs={"adapters": adapters, "loop": loop},
|
|
||||||
daemon=True,
|
|
||||||
name=f"cron-misfire-{job_id[:12]}",
|
name=f"cron-misfire-{job_id[:12]}",
|
||||||
).start()
|
).start()
|
||||||
fired += 1
|
fired += 1
|
||||||
@@ -356,17 +336,8 @@ class InProcessCronScheduler(CronScheduler):
|
|||||||
return "builtin"
|
return "builtin"
|
||||||
|
|
||||||
def start(
|
def start(
|
||||||
self,
|
self, stop_event, *, adapters=None, loop=None, interval=60, can_dispatch=None,
|
||||||
stop_event,
|
profile_homes=None, profile_adapters=None, default_profile=None, profile_gate=None,
|
||||||
*,
|
|
||||||
adapters=None,
|
|
||||||
loop=None,
|
|
||||||
interval=60,
|
|
||||||
can_dispatch=None,
|
|
||||||
profile_homes=None,
|
|
||||||
profile_adapters=None,
|
|
||||||
default_profile=None,
|
|
||||||
profile_gate=None,
|
|
||||||
):
|
):
|
||||||
from cron.scheduler import CronTickYielded
|
from cron.scheduler import CronTickYielded
|
||||||
from cron.scheduler import tick as cron_tick
|
from cron.scheduler import tick as cron_tick
|
||||||
@@ -377,15 +348,9 @@ class InProcessCronScheduler(CronScheduler):
|
|||||||
# Multiplex: tick EACH profile's store every cycle, heartbeats/recovery scoped per profile.
|
# Multiplex: tick EACH profile's store every cycle, heartbeats/recovery scoped per profile.
|
||||||
if profile_homes:
|
if profile_homes:
|
||||||
self._start_multiplex(
|
self._start_multiplex(
|
||||||
stop_event,
|
stop_event, profile_homes=profile_homes, adapters=adapters, loop=loop,
|
||||||
profile_homes=profile_homes,
|
interval=interval, can_dispatch=can_dispatch, profile_adapters=profile_adapters,
|
||||||
adapters=adapters,
|
default_profile=default_profile, profile_gate=profile_gate,
|
||||||
loop=loop,
|
|
||||||
interval=interval,
|
|
||||||
can_dispatch=can_dispatch,
|
|
||||||
profile_adapters=profile_adapters,
|
|
||||||
default_profile=default_profile,
|
|
||||||
profile_gate=profile_gate,
|
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -423,26 +388,15 @@ class InProcessCronScheduler(CronScheduler):
|
|||||||
stop_event.wait(_backoff_wait_seconds(interval, consecutive_failures))
|
stop_event.wait(_backoff_wait_seconds(interval, consecutive_failures))
|
||||||
|
|
||||||
def _start_multiplex(
|
def _start_multiplex(
|
||||||
self,
|
self, stop_event, *, profile_homes, adapters=None, loop=None, interval=60,
|
||||||
stop_event,
|
can_dispatch=None, profile_adapters=None, default_profile=None, profile_gate=None,
|
||||||
*,
|
|
||||||
profile_homes,
|
|
||||||
adapters=None,
|
|
||||||
loop=None,
|
|
||||||
interval=60,
|
|
||||||
can_dispatch=None,
|
|
||||||
profile_adapters=None,
|
|
||||||
default_profile=None,
|
|
||||||
profile_gate=None,
|
|
||||||
):
|
):
|
||||||
"""Tick every profile's store, each scoped via ``_profile_cron_scope``. ``profile_gate(name,
|
"""Tick every profile's store, each scoped via ``_profile_cron_scope``. ``profile_gate(name,
|
||||||
home)``, when given, is consulted every cycle; a rejected profile is neither ticked nor
|
home)``, when given, is consulted every cycle; a rejected profile is neither ticked nor
|
||||||
heartbeated."""
|
heartbeated."""
|
||||||
from cron.scheduler import tick as cron_tick
|
from cron.scheduler import tick as cron_tick
|
||||||
from cron.scheduler import (
|
from cron.scheduler import (
|
||||||
CronTickYielded,
|
CronTickYielded, SharedRouteAdapters, _is_fd_exhaustion,
|
||||||
SharedRouteAdapters,
|
|
||||||
_is_fd_exhaustion,
|
|
||||||
_primary_profile_routes_for_current_home,
|
_primary_profile_routes_for_current_home,
|
||||||
)
|
)
|
||||||
from cron.jobs import clear_ticker_error, record_ticker_error, record_ticker_heartbeat
|
from cron.jobs import clear_ticker_error, record_ticker_error, record_ticker_heartbeat
|
||||||
@@ -496,11 +450,8 @@ class InProcessCronScheduler(CronScheduler):
|
|||||||
try:
|
try:
|
||||||
with _profile_cron_scope(home):
|
with _profile_cron_scope(home):
|
||||||
cron_tick(
|
cron_tick(
|
||||||
verbose=False,
|
verbose=False, adapters=tick_adapters_for(_pname), loop=loop,
|
||||||
adapters=tick_adapters_for(_pname),
|
sync=False, can_dispatch=can_dispatch,
|
||||||
loop=loop,
|
|
||||||
sync=False,
|
|
||||||
can_dispatch=can_dispatch,
|
|
||||||
)
|
)
|
||||||
except CronTickYielded as e:
|
except CronTickYielded as e:
|
||||||
# Yield for THIS profile only; one fresh gateway must not stop others.
|
# Yield for THIS profile only; one fresh gateway must not stop others.
|
||||||
|
|||||||
@@ -130,9 +130,7 @@ def main() -> int:
|
|||||||
prompt = _build_prompt(items, args.criteria)
|
prompt = _build_prompt(items, args.criteria)
|
||||||
try:
|
try:
|
||||||
resp = call_llm(
|
resp = call_llm(
|
||||||
task="monitor",
|
task="monitor", messages=[{"role": "user", "content": prompt}], max_tokens=1024,
|
||||||
messages=[{"role": "user", "content": prompt}],
|
|
||||||
max_tokens=1024,
|
|
||||||
temperature=0,
|
temperature=0,
|
||||||
)
|
)
|
||||||
content = resp.choices[0].message.content
|
content = resp.choices[0].message.content
|
||||||
|
|||||||
@@ -116,8 +116,7 @@ CATALOG: List[CatalogEntry] = [
|
|||||||
|
|
||||||
|
|
||||||
def seed_catalog_suggestions(
|
def seed_catalog_suggestions(
|
||||||
*,
|
*, add_fn: Optional[Callable[..., Optional[Dict[str, Any]]]] = None,
|
||||||
add_fn: Optional[Callable[..., Optional[Dict[str, Any]]]] = None,
|
|
||||||
keys: Optional[List[str]] = None,
|
keys: Optional[List[str]] = None,
|
||||||
) -> List[Dict[str, Any]]:
|
) -> List[Dict[str, Any]]:
|
||||||
"""Register catalog entries as pending suggestions.
|
"""Register catalog entries as pending suggestions.
|
||||||
|
|||||||
+2
-8
@@ -111,12 +111,7 @@ def list_pending() -> List[Dict[str, Any]]:
|
|||||||
|
|
||||||
|
|
||||||
def add_suggestion(
|
def add_suggestion(
|
||||||
*,
|
*, title: str, description: str, source: str, job_spec: Dict[str, Any], dedup_key: str,
|
||||||
title: str,
|
|
||||||
description: str,
|
|
||||||
source: str,
|
|
||||||
job_spec: Dict[str, Any],
|
|
||||||
dedup_key: str,
|
|
||||||
) -> Optional[Dict[str, Any]]:
|
) -> Optional[Dict[str, Any]]:
|
||||||
"""Register a pending suggestion. Returns the record, or None when skipped: the same ``dedup_key``
|
"""Register a pending suggestion. Returns the record, or None when skipped: the same ``dedup_key``
|
||||||
was already decided on or is still pending (never re-offer, never duplicate), or the pending list
|
was already decided on or is still pending (never re-offer, never duplicate), or the pending list
|
||||||
@@ -197,8 +192,7 @@ def accept_suggestion(ref: str, *, origin: Optional[Dict[str, Any]] = None) -> O
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
from cron.scheduler import (
|
from cron.scheduler import (
|
||||||
CronSchedulerRegistrationError,
|
CronSchedulerRegistrationError, create_job_with_scheduler_registration,
|
||||||
create_job_with_scheduler_registration,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
spec = dict(s.get("job_spec") or {})
|
spec = dict(s.get("job_spec") or {})
|
||||||
|
|||||||
Reference in New Issue
Block a user