Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
0.10.2
-----
- Prevent disabled taps from being included in smart scheduling calculations
- Reset the smart_interval_mask when running spread_schedules
- Modify evaluation criteria to disincentivise overlaps for the first minute of the run

0.10.1
-----
- Fix bug in delete_schedule introduced in 0.10.0
Expand Down
10 changes: 5 additions & 5 deletions cicada/commands/smart_schedule.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,18 @@ def _create_schedule_objects(schedule_ids, db_cur):
# Fetch details for each schedule and convert to Schedule objects
for schedule_id in schedule_ids:
details = scheduler.get_schedule_details(db_cur, schedule_id)
if schedule_id in blocklisted_schedules:
details['blocklisted'] = True
else:
details['blocklisted'] = False
if details['is_enabled'] == 0:
print(f"Skipping disabled schedule {schedule_id}")
continue
details['blocklisted'] = schedule_id in blocklisted_schedules

try:
schedule = Schedule(
schedule_id = details['schedule_id'],
server_id = details['server_id'],
interval_mask = details['interval_mask'],
smart_interval_mask = details.get('smart_interval_mask'),
blocklisted = details.get('blocklisted', False),
blocklisted = details['blocklisted'],
db_cur = db_cur
)
# Ignore the few schedules that have irregular cron expressions for now.
Expand Down
1 change: 1 addition & 0 deletions cicada/commands/spread_schedules.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ def main(spread_details, dbname=None):
current_schedule_details = scheduler.get_schedule_details(db_cur, schedule_id)
new_schedule_details = current_schedule_details.copy()
new_schedule_details["server_id"] = valid_target_servers[next_enabled_server]
new_schedule_details["smart_interval_mask"] = None # Reset smart_interval_mask to None when spreading schedules
Comment thread
naomiwise marked this conversation as resolved.

next_enabled_server += 1
if next_enabled_server == valid_server_count:
Expand Down
3 changes: 2 additions & 1 deletion cicada/lib/smart_scheduling/evaluation.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ def evaluate_usage_and_peak(start_times: Sequence[int], schedules: Sequence[Sche
# schedule runs in, we add the usage at the starting minute and subtract it at the end minute.
while minute < mins_per_day:
end = min(minute + run_time, mins_per_day)
diff[minute] += 1
diff[minute] += 2
diff[minute+1] -= 1
diff[end] -= 1
minute += freq

Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

setup(
name="cicada",
version="0.10.1",
version="0.10.2",
description="Lightweight, agent-based, distributed scheduler",
long_description=long_description,
long_description_content_type="text/markdown",
Expand Down
84 changes: 60 additions & 24 deletions tests/test_smart_scheduling.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,10 +167,11 @@ def test_evaluate_single_schedule_no_overlap(self, db_setup):
usage, peak = evaluate_usage_and_peak(start_blocks, [test_schedule])

assert usage.shape == (1440,)
assert peak == 1
assert peak == 2
for i in range(24):
mins = i * 60
assert (usage[mins : mins + 5] == 1).all()
assert (usage[mins] == 2)
assert (usage[mins + 1 : mins + 5] == 1).all()
assert (usage[mins + 5 : (i + 1) * 60] == 0).all()
finally:
db_cur.close()
Expand Down Expand Up @@ -219,11 +220,13 @@ def test_evaluate_multiple_schedules_no_overlap(self, db_setup):
start_blocks = [0, 30]
usage, peak = evaluate_usage_and_peak(start_blocks, [schedule1, schedule2])

assert (usage[0:5] == 1).all()
assert (usage[0] == 2)
assert (usage[1:5] == 1).all()
assert (usage[6:30] == 0.0).all()
assert (usage[30:35] == 1).all()
assert (usage[30] == 2)
assert (usage[31:35] == 1).all()
assert (usage[35:60] == 0.0).all()
assert peak == 1
assert peak == 2
finally:
db_cur.close()
db_conn.close()
Expand Down Expand Up @@ -271,8 +274,8 @@ def test_evaluate_overlapping_schedules(self, db_setup):
start_blocks = [0, 0]
usage, peak = evaluate_usage_and_peak(start_blocks, [schedule1, schedule2])

assert peak == 2
assert usage[0] == 2
assert peak == 4
assert usage[0] == 4
assert usage[5] == 1
finally:
db_cur.close()
Expand Down Expand Up @@ -883,6 +886,39 @@ def test_multiple_overlapping_schedules_evaluation(self, db_setup):
db_cur.close()
db_conn.close()

def test_create_schedule_objects_skips_disabled_schedules(self, db_setup):
"""Test that _create_schedule_objects skips disabled schedules"""
db_conn, db_cur = get_db_cursor()
try:
# Setup: Create server and schedules
query_test_db(
"""INSERT INTO servers (server_id, hostname, fqdn, ip4_address)
Comment thread
naomiwise marked this conversation as resolved.
VALUES (1, 'test-server', 'test-server.local', '192.168.1.1')"""
)
query_test_db(
"""INSERT INTO schedules (schedule_id, server_id, interval_mask, exec_command, is_enabled)
VALUES ('sched-1', 1, '0 * * * *', 'echo test1', 1),
('sched-2', 1, '*/30 * * * *', 'echo test2', 0),
('sched-3', 1, '*/15 * * * *', 'echo test3', 1),
('sched-4', 1, '0 0 * * *', 'echo test4', 0)"""
)

# Get schedule IDs and create Schedule objects
schedule_ids = ['sched-1', 'sched-2', 'sched-3', 'sched-4']
schedules = smart_schedule._create_schedule_objects(schedule_ids, db_cur)

# Verify that disabled schedules were skipped
assert len(schedules) == 2, f"Expected 2 enabled schedules, got {len(schedules)}"

enabled_schedule_ids = [s.schedule_id for s in schedules]
assert 'sched-1' in enabled_schedule_ids, "Enabled schedule 'sched-1' should be included"
assert 'sched-3' in enabled_schedule_ids, "Enabled schedule 'sched-3' should be included"
assert 'sched-2' not in enabled_schedule_ids, "Disabled schedule 'sched-2' should be skipped"
assert 'sched-4' not in enabled_schedule_ids, "Disabled schedule 'sched-4' should be skipped"
finally:
db_cur.close()
db_conn.close()


class TestSmartSchedulingCommand:
"""Tests for the smart scheduling command"""
Expand Down Expand Up @@ -1280,12 +1316,12 @@ def test_optimise_with_custom_db_connection_single_server(self, db_setup):
VALUES (1, 'test-server', 'test-server.local', '192.168.1.1')"""
)
query_test_db(
"""INSERT INTO schedules (schedule_id, server_id, interval_mask, exec_command)
VALUES ('sched-1', 1, '*/10 * * * *', 'echo test1'),
('sched-2', 1, '0 * * * *', 'echo test2'),
('sched-3', 1, '0 * * * *', 'echo test3'),
('sched-4', 1, '0 * * * *', 'echo test4'),
('sched-5', 1, '0 * * * *', 'echo test5')"""
"""INSERT INTO schedules (schedule_id, server_id, interval_mask, exec_command, is_enabled)
VALUES ('sched-1', 1, '*/10 * * * *', 'echo test1', 1),
('sched-2', 1, '0 * * * *', 'echo test2', 1),
('sched-3', 1, '0 * * * *', 'echo test3', 1),
('sched-4', 1, '0 * * * *', 'echo test4', 1),
('sched-5', 1, '0 * * * *', 'echo test5', 1)"""
)

# Call optimise with custom db_cur
Expand Down Expand Up @@ -1323,17 +1359,17 @@ def test_optimise_with_custom_db_connection_multiple_servers(self, db_setup):
(2, 'server-2', 'server-2.local', '192.168.1.2')"""
)
query_test_db(
"""INSERT INTO schedules (schedule_id, server_id, interval_mask, exec_command)
VALUES ('sched-1a', 1, '*/10 * * * *', 'echo test1'),
('sched-2a', 1, '0 * * * *', 'echo test2'),
('sched-3a', 1, '0 * * * *', 'echo test3'),
('sched-4a', 1, '0 * * * *', 'echo test4'),
('sched-5a', 1, '0 * * * *', 'echo test5'),
('sched-1b', 2, '*/10 * * * *', 'echo test1'),
('sched-2b', 2, '0 * * * *', 'echo test2'),
('sched-3b', 2, '0 * * * *', 'echo test3'),
('sched-4b', 2, '0 * * * *', 'echo test4'),
('sched-5b', 2, '0 * * * *', 'echo test5')
"""INSERT INTO schedules (schedule_id, server_id, interval_mask, exec_command, is_enabled)
VALUES ('sched-1a', 1, '*/10 * * * *', 'echo test1', 1),
('sched-2a', 1, '0 * * * *', 'echo test2', 1),
('sched-3a', 1, '0 * * * *', 'echo test3', 1),
('sched-4a', 1, '0 * * * *', 'echo test4', 1),
('sched-5a', 1, '0 * * * *', 'echo test5', 1),
('sched-1b', 2, '*/10 * * * *', 'echo test1', 1),
('sched-2b', 2, '0 * * * *', 'echo test2', 1),
('sched-3b', 2, '0 * * * *', 'echo test3', 1),
('sched-4b', 2, '0 * * * *', 'echo test4', 1),
('sched-5b', 2, '0 * * * *', 'echo test5', 1)
"""
)

Expand Down
Loading