Add scheduler job name uniqueness and prereqs for SQLite executor#297
Add scheduler job name uniqueness and prereqs for SQLite executor#297NodeJSmith merged 3 commits intomainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This PR introduces prerequisite changes needed for the SQLite command executor feature (#264). The changes focus on job name uniqueness validation, idempotent job registration, clearer naming for timing metrics, and improved reconnection handling.
Changes:
- Added
App.app_keyproperty for accessing the app's configuration key from its manifest - Enforced job name uniqueness per scheduler instance with
if_existsparameter ("error"|"skip") for idempotent registration - Renamed
ExecutionResult.started_attomonotonic_startto clarify it stores monotonic clock values, not wall-clock timestamps - Implemented
__eq__/__hash__on trigger classes for configuration-based comparison - Fixed StateProxy disconnect to use
scheduler.remove_job()instead ofjob.cancel()to properly free the job name slot
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| src/hassette/app/app.py | Added app_key property that delegates to app_manifest.app_key |
| src/hassette/utils/execution.py | Renamed started_at to monotonic_start in ExecutionResult |
| src/hassette/scheduler/scheduler.py | Added _jobs_by_name tracking, if_exists parameter on all run methods, and name uniqueness validation |
| src/hassette/scheduler/classes.py | Added ScheduledJob.matches() method and __eq__/__hash__ to IntervalTrigger and CronTrigger |
| src/hassette/core/state_proxy.py | Changed disconnect to use remove_job() instead of cancel() and added if_exists="skip" to polling job |
| tests/unit/test_scheduler_job_names.py | Comprehensive tests for job name uniqueness and if_exists behavior |
| tests/unit/test_func_utils.py | Tests for callable_name() and callable_short_name() edge cases |
| tests/unit/test_app_key.py | Test for App.app_key property |
| tests/unit/test_execution.py | Updated tests for monotonic_start rename |
| tests/integration/test_scheduler.py | Added explicit job names to prevent uniqueness conflicts |
| CHANGELOG.md | Documented all changes including breaking changes |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Prerequisite changes for SQLite command executor (#264): - Add App.app_key property delegating to app_manifest - Enforce job name uniqueness per Scheduler instance with if_exists parameter ("error"|"skip") on all run_* methods - Add ScheduledJob.matches() and __eq__/__hash__ on trigger classes for configuration-based comparison - Rename ExecutionResult.started_at to monotonic_start - Fix StateProxy.on_disconnect to use remove_job() instead of cancel() so the name slot is freed for reconnection - Add tests for callable_name/callable_short_name edge cases
app_manifest is a ClassVar annotation with no default value — it only exists at runtime when set by the app registry. With random test ordering in CI, patch.object fails if no other test has set the attribute first.
f9030de to
072a896
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #297 +/- ##
==========================================
+ Coverage 79.63% 79.81% +0.17%
==========================================
Files 131 131
Lines 9297 9325 +28
Branches 927 931 +4
==========================================
+ Hits 7404 7443 +39
+ Misses 1526 1520 -6
+ Partials 367 362 -5 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Summary
Prerequisite changes for the SQLite command executor (#264):
_jobs_by_namedict tracking. Addsif_existsparameter ("error"|"skip") toadd_job()and allrun_*methods for idempotent registration.ScheduledJob.matches()compares callable, trigger, repeat, args, and kwargs to determine if an existing job is logically identical__eq__/__hash__onIntervalTrigger(compares interval) andCronTrigger(compares cron expression) for configuration-based comparison, excluding runtime state likestartstarted_at→monotonic_startto clarify it stores a monotonic clock value, not a wall-clock timestampon_disconnect()now callsscheduler.remove_job()instead ofjob.cancel()to properly free the name slot, andsubscribe_to_events()usesif_exists="skip"for idempotent reconnectionBreaking changes
ValueErroron duplicate job names (previously allowed)ExecutionResult.started_atrenamed tomonotonic_startCloses #264