programgarden 2.5.4__tar.gz → 2.5.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {programgarden-2.5.4 → programgarden-2.5.5}/PKG-INFO +1 -1
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/context.py +1 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/executor.py +23 -6
- {programgarden-2.5.4 → programgarden-2.5.5}/pyproject.toml +1 -1
- {programgarden-2.5.4 → programgarden-2.5.5}/README.md +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/__init__.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/binding_validator.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/client.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/code_worker.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/database/__init__.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/database/adjustment_delivery.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/database/broker_evidence.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/database/broker_order_totals.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/database/broker_snapshot.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/database/checkpoint_manager.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/database/db_naming.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/database/execution_storage.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/database/fill_reconciler.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/database/order_cancellation.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/database/order_recovery.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/database/owned_order_cancellation.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/database/position_reconciliation.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/database/query_builder.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/database/workflow_position_tracker.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/database/workflow_risk_tracker.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/deep_fixtures.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/futures_orderable.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/futures_pnl.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/futures_read_evidence.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/incremental_build.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/managed_order_control.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/node_runner.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/order_lifecycle.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/plugin/__init__.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/plugin/sandbox.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/providers/__init__.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/providers/llm_errors.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/providers/llm_provider.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/reconnect_handler.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/replay_contracts.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/replay_events.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/replay_external.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/replay_order_adapter.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/replay_orders.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/replay_scenarios.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/replay_semantics.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/replay_sources.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/replay_sqlite.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/replay_triggers.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/resolver.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/resource/__init__.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/resource/context.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/resource/limiter.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/resource/monitor.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/resource/throttle.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/semantic_rules.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/tools/__init__.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/tools/credential_tools.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/tools/definition_tools.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/tools/event_tools.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/tools/job_tools.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/tools/registry_tools.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/tools/sqlite_tools.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/validation_recommender.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/validation_replay.py +0 -0
- {programgarden-2.5.4 → programgarden-2.5.5}/programgarden/valuation.py +0 -0
|
@@ -260,6 +260,7 @@ class ExecutionContext:
|
|
|
260
260
|
# Stores trackers/connections that should stay alive between flow executions
|
|
261
261
|
self._persistent_nodes: Dict[str, Any] = {} # node_id -> tracker/connection
|
|
262
262
|
self._persistent_tasks: Dict[str, asyncio.Task] = {} # node_id -> background task
|
|
263
|
+
self._schedule_tick_source: Optional[str] = None # Only this timer may trigger the current cycle.
|
|
263
264
|
self._persistent_metadata: Dict[str, Dict[str, Any]] = {} # node_id -> {key: value}
|
|
264
265
|
|
|
265
266
|
# === New: Order Event Dispatcher ===
|
|
@@ -2227,12 +2227,12 @@ class ScheduleNodeExecutor(NodeExecutorBase):
|
|
|
2227
2227
|
) -> Dict[str, Any]:
|
|
2228
2228
|
from datetime import datetime
|
|
2229
2229
|
from zoneinfo import ZoneInfo
|
|
2230
|
-
from croniter import croniter
|
|
2230
|
+
from croniter import croniter, CroniterBadDateError
|
|
2231
2231
|
|
|
2232
2232
|
# 이미 스케줄러가 실행 중이면 재등록하지 않음 (schedule_tick 이벤트로 인한 재실행 시)
|
|
2233
2233
|
if node_id in context._persistent_tasks:
|
|
2234
2234
|
context.log("debug", f"Scheduler already running for {node_id}, skip", node_id)
|
|
2235
|
-
return {"trigger":
|
|
2235
|
+
return {"trigger": bool(context.is_dry_run or context._schedule_tick_source == node_id)}
|
|
2236
2236
|
|
|
2237
2237
|
# ⑭ cron is required — NO silent "*/5 * * * *" fallback. A missing cron
|
|
2238
2238
|
# used to make the schedule quietly run every 5 minutes ("looks fine,
|
|
@@ -2305,7 +2305,7 @@ class ScheduleNodeExecutor(NodeExecutorBase):
|
|
|
2305
2305
|
try:
|
|
2306
2306
|
# second_at_beginning=True로 초 단위 cron도 지원
|
|
2307
2307
|
try:
|
|
2308
|
-
itr = croniter(cron_expr, datetime.now(tz), second_at_beginning=True)
|
|
2308
|
+
itr = croniter(cron_expr, datetime.now(tz), second_at_beginning=True, max_years_between_matches=130)
|
|
2309
2309
|
except TypeError:
|
|
2310
2310
|
itr = croniter(cron_expr, datetime.now(tz))
|
|
2311
2311
|
|
|
@@ -2340,7 +2340,12 @@ class ScheduleNodeExecutor(NodeExecutorBase):
|
|
|
2340
2340
|
)
|
|
2341
2341
|
break
|
|
2342
2342
|
# 다음 실행 시간 계산
|
|
2343
|
-
|
|
2343
|
+
try:
|
|
2344
|
+
next_dt = itr.get_next(datetime)
|
|
2345
|
+
except CroniterBadDateError:
|
|
2346
|
+
# A calendar date/year can be exhausted. It is not an
|
|
2347
|
+
# execution failure and must never roll into another year.
|
|
2348
|
+
break
|
|
2344
2349
|
now = datetime.now(tz)
|
|
2345
2350
|
delay = (next_dt - now).total_seconds()
|
|
2346
2351
|
|
|
@@ -2421,8 +2426,9 @@ class ScheduleNodeExecutor(NodeExecutorBase):
|
|
|
2421
2426
|
task = asyncio.create_task(scheduler_task())
|
|
2422
2427
|
context.register_persistent_task(node_id, task)
|
|
2423
2428
|
|
|
2424
|
-
#
|
|
2425
|
-
|
|
2429
|
+
# Register the timer without executing downstream trading work early.
|
|
2430
|
+
# Explicit dry-run simulation still exercises one synthetic cycle.
|
|
2431
|
+
return {"trigger": bool(context.is_dry_run)}
|
|
2426
2432
|
|
|
2427
2433
|
|
|
2428
2434
|
class WatchlistNodeExecutor(NodeExecutorBase):
|
|
@@ -23557,6 +23563,14 @@ class WorkflowJob:
|
|
|
23557
23563
|
event = await self.context.wait_for_event(timeout=1.0)
|
|
23558
23564
|
|
|
23559
23565
|
if event is None:
|
|
23566
|
+
has_realtime_source = any(
|
|
23567
|
+
self.workflow.nodes[n].node_type in REALTIME_NODE_TYPES
|
|
23568
|
+
for n in self._stay_connected_nodes
|
|
23569
|
+
)
|
|
23570
|
+
if (self._has_schedule_node and not has_realtime_source
|
|
23571
|
+
and all(task.done() for task in self.context._persistent_tasks.values())):
|
|
23572
|
+
# Finite calendar/count schedules finish after queued ticks drain.
|
|
23573
|
+
break
|
|
23560
23574
|
continue
|
|
23561
23575
|
|
|
23562
23576
|
# Wait if paused
|
|
@@ -23595,6 +23609,7 @@ class WorkflowJob:
|
|
|
23595
23609
|
# RuntimeError 등)가 스케줄 잡 전체를 종료시키지 않도록 한다.
|
|
23596
23610
|
# 실패 사이클은 silent 하지 않게 'cycle_failed' 로 통지하고
|
|
23597
23611
|
# 다음 tick 에서 재시도한다 (24시간 무인 운영 보호).
|
|
23612
|
+
self.context._schedule_tick_source = event.source_node_id
|
|
23598
23613
|
try:
|
|
23599
23614
|
await self._execute_main_flow()
|
|
23600
23615
|
except Exception as cycle_err:
|
|
@@ -23606,6 +23621,8 @@ class WorkflowJob:
|
|
|
23606
23621
|
await self.context.notify_job_state("cycle_failed", self.stats)
|
|
23607
23622
|
else:
|
|
23608
23623
|
await self.context.notify_job_state("cycle_completed", self.stats)
|
|
23624
|
+
finally:
|
|
23625
|
+
self.context._schedule_tick_source = None
|
|
23609
23626
|
|
|
23610
23627
|
logger.info("Event loop ended")
|
|
23611
23628
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{programgarden-2.5.4 → programgarden-2.5.5}/programgarden/database/owned_order_cancellation.py
RENAMED
|
File without changes
|
{programgarden-2.5.4 → programgarden-2.5.5}/programgarden/database/position_reconciliation.py
RENAMED
|
File without changes
|
|
File without changes
|
{programgarden-2.5.4 → programgarden-2.5.5}/programgarden/database/workflow_position_tracker.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|