-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathpostgres_example.py
More file actions
163 lines (130 loc) · 5.12 KB
/
Copy pathpostgres_example.py
File metadata and controls
163 lines (130 loc) · 5.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
"""Example: Using PostgreSQL adapter with Chronis.
This example demonstrates how to use PostgreSQL for job storage with
automatic database migrations.
Requirements:
pip install chronis[postgres]
# Or manually: pip install psycopg2-binary
PostgreSQL Server:
docker-compose up -d
# Or: brew install postgresql && brew services start postgresql
Database Migrations:
The PostgreSQL adapter uses a Flyway-style migration system.
Tables and indexes are created automatically on first run.
Migration history is tracked in 'chronis_migration_history' table.
"""
import time
import psycopg2
from chronis import PollingScheduler
from chronis.adapters.lock import InMemoryLock
from chronis.contrib.adapters.storage import PostgreSQLStorage
def send_notification(**extra):
"""Example job function."""
print(f"[{time.strftime('%H:%M:%S')}] Sending notification...")
def generate_report(**extra):
"""Another example job function."""
print(f"[{time.strftime('%H:%M:%S')}] Generating report...")
def main():
"""Run the example."""
print("=== Chronis PostgreSQL Adapter Example ===\n")
# 1. Connect to PostgreSQL
print("1. Connecting to PostgreSQL...")
try:
conn = psycopg2.connect(
host="localhost",
port=5432,
database="scheduler",
user="scheduler",
password="scheduler_pass",
)
print(" ✓ PostgreSQL connection successful\n")
except psycopg2.OperationalError as e:
print(f" ✗ PostgreSQL connection failed: {e}")
print(" Start PostgreSQL: docker-compose up -d")
return
try:
# 2. Create adapters (automatic migrations)
print("2. Creating PostgreSQL storage adapter...")
print(" Running database migrations...")
storage = PostgreSQLStorage(conn)
lock = InMemoryLock() # Use Redis for production
print(" ✓ Adapters created")
print(" ✓ Database migrations applied")
print(" ✓ Tables: chronis_jobs, chronis_migration_history\n")
# 3. Create scheduler
print("3. Creating scheduler...")
scheduler = PollingScheduler(
storage_adapter=storage, lock_adapter=lock, polling_interval_seconds=5, verbose=True
)
print(" ✓ Scheduler created\n")
# 4. Register functions
print("4. Registering job functions...")
scheduler.register_job_function("send_notification", send_notification)
scheduler.register_job_function("generate_report", generate_report)
print(" ✓ Functions registered\n")
# 5. Create jobs
print("5. Creating jobs...")
# Interval job
job1 = scheduler.create_interval_job(
func="send_notification",
job_id="notification-job",
name="Notification Sender",
seconds=15,
metadata={"tenant_id": "acme", "priority": "high"},
)
print(f" ✓ Created: {job1.job_id}")
# Cron job
job2 = scheduler.create_cron_job(
func="generate_report",
job_id="report-job",
name="Report Generator",
minute="*/2", # Every 2 minutes
metadata={"tenant_id": "acme", "type": "daily_report"},
)
print(f" ✓ Created: {job2.job_id}\n")
# 6. Start scheduler
print("6. Starting scheduler...")
scheduler.start()
print(" ✓ Scheduler started\n")
# 7. Monitor
print("7. Running for 30 seconds... (Ctrl+C to stop)\n")
for i in range(6):
time.sleep(5)
# Query jobs from PostgreSQL
jobs = scheduler.query_jobs()
print(f" [{i * 5}s] Jobs in database: {len(jobs)}")
for job in jobs:
print(
f" - {job.job_id}: {job.status.value} "
f"(next: {job.next_run_time_local or 'N/A'})"
)
# Query database directly
with conn.cursor() as cursor:
cursor.execute("SELECT COUNT(*) FROM chronis_jobs")
count = cursor.fetchone()[0]
print(f" [{i * 5}s] PostgreSQL row count: {count}\n")
except KeyboardInterrupt:
print("\n Interrupted by user")
finally:
# 8. Cleanup
print("\n8. Cleaning up...")
scheduler.stop()
print(" ✓ Scheduler stopped")
# Delete jobs
scheduler.delete_job("notification-job")
scheduler.delete_job("report-job")
print(" ✓ Jobs deleted")
# Verify cleanup
with conn.cursor() as cursor:
cursor.execute("SELECT COUNT(*) FROM chronis_jobs")
remaining = cursor.fetchone()[0]
if remaining > 0:
print(f" ⚠ {remaining} jobs remaining in database")
cursor.execute("DELETE FROM chronis_jobs")
conn.commit()
print(" ✓ Cleaned up remaining jobs")
else:
print(" ✓ All jobs cleaned up")
conn.close()
print("\n=== Example completed ===")
if __name__ == "__main__":
main()