Skip to content

Commit

Permalink
add test for when max_backoff_delay_seconds_less_than_minimum and mak…
Browse files Browse the repository at this point in the history
…e max_backoff_delay_seconds unbounded
  • Loading branch information
amamd07 committed Jan 23, 2025
1 parent 4dd767b commit 95eaba5
Show file tree
Hide file tree
Showing 5 changed files with 24 additions and 14 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ w.sleep_delay = 3
w.max_attempts = 5

# sets a cap on how long a worker should wait between retry attempts.
# if not set, the backoff delay time will grow exponentially (default 60)
# if not set, the backoff delay time will grow exponentially (minimum is 5)
w.max_backoff_delay_seconds = 60

# maximum run time allowed for the job, before it expires (default 3600)
Expand Down
2 changes: 1 addition & 1 deletion pyworker/job.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def __init__(self, class_name, database, logger,
self.job_name = '%s#run' % class_name
self.attempts = attempts
if max_backoff_delay_seconds:
max_backoff_delay_seconds = max(max_backoff_delay_seconds, 2) # max_backoff_delay_seconds can not be less than 2 seconds
max_backoff_delay_seconds = max(max_backoff_delay_seconds, 5) # max_backoff_delay_seconds can not be less than 5 seconds
self.max_backoff_delay_seconds = max_backoff_delay_seconds
self.run_at = run_at
self.queue = queue
Expand Down
5 changes: 3 additions & 2 deletions pyworker/worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,16 @@ class TerminatedException(Exception): pass
class Worker(object):
def __init__(self, dbstring, logger=None,
extra_delayed_job_fields=None,
reported_attributes_prefix=''):
reported_attributes_prefix='',
max_backoff_delay_seconds=None):
super(Worker, self).__init__()
self.logger = Logger(logger)
self.logger.info('Starting pyworker...')
self.database = DBConnector(dbstring, self.logger)
self.sleep_delay = 10
self.max_attempts = 3
self.max_run_time = 3600
self.max_backoff_delay_seconds = 60
self.max_backoff_delay_seconds = max_backoff_delay_seconds
self.queue_names = 'default'
hostname = os.uname()[1]
pid = os.getpid()
Expand Down
27 changes: 18 additions & 9 deletions tests/test_job.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def load_fixture(self, filename):
with open('tests/fixtures/%s' % filename) as f:
return f.read()

def load_job(self, filename):
def load_job(self, filename, max_backoff_delay_seconds=None):
mock_handler = self.load_fixture(filename)
mock_row = (
self.mock_job_id,
Expand All @@ -43,7 +43,9 @@ def load_job(self, filename):
)
return Job.from_row(mock_row,
self.mock_max_attempts,
MagicMock(), MagicMock())
MagicMock(), MagicMock(),
max_backoff_delay_seconds=max_backoff_delay_seconds
)

def load_job_with_extra_fields(self, filename):
mock_handler = self.load_fixture(filename)
Expand Down Expand Up @@ -71,8 +73,8 @@ def load_unregistered_job_with_reporter(self, reporter):
job.reporter = reporter
return job

def load_registered_job(self):
job = self.load_job('handler_registered.yaml')
def load_registered_job(self, max_backoff_delay_seconds=None):
job = self.load_job('handler_registered.yaml', max_backoff_delay_seconds=max_backoff_delay_seconds)
job.error = MagicMock()
job.failure = MagicMock()
job._update_job = MagicMock()
Expand Down Expand Up @@ -215,8 +217,7 @@ def test_set_error_unlock_if_max_attempts_not_exceeded_updates_run_at_exponentia
def test_set_error_unlock_if_delta_doesnt_exceed_max_backoff_delay_seconds(
self, mock_get_current_time):
mock_get_current_time.return_value = self.mock_now
job = self.load_registered_job()
job.max_backoff_delay_seconds = 8
job = self.load_registered_job(max_backoff_delay_seconds=8)

self.assert_job_updated_run_at(job, attempts=0, expected_value=datetime.datetime(2023, 10, 7, 0, 0, 6))

Expand All @@ -225,10 +226,18 @@ def test_set_error_unlock_if_delta_doesnt_exceed_max_backoff_delay_seconds(
def test_set_error_unlock_if_delta_exceeds_max_backoff_delay_seconds(
self, mock_get_current_time):
mock_get_current_time.return_value = self.mock_now
job = self.load_registered_job()
job.max_backoff_delay_seconds = 2
job = self.load_registered_job(max_backoff_delay_seconds=5)

self.assert_job_updated_run_at(job, attempts=0, expected_value=datetime.datetime(2023, 10, 7, 0, 0, 5))

## run_at
@patch('pyworker.job.get_current_time')
def test_set_error_unlock_if_max_backoff_delay_seconds_less_than_minimum(
self, mock_get_current_time):
mock_get_current_time.return_value = self.mock_now
job = self.load_registered_job(max_backoff_delay_seconds=2)

self.assert_job_updated_run_at(job, attempts=0, expected_value=datetime.datetime(2023, 10, 7, 0, 0, 2))
self.assert_job_updated_run_at(job, attempts=0, expected_value=datetime.datetime(2023, 10, 7, 0, 0, 5))

@patch('pyworker.job.get_current_time')
def test_set_error_unlock_if_max_attempts_not_exceeded_updates_run_at_exponentially_when_attempts_1(
Expand Down
2 changes: 1 addition & 1 deletion tests/test_worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def tearDown(self):
@patch('pyworker.worker.os.getpid', return_value=1234)
@patch('pyworker.worker.DBConnector')
def test_worker_init(self, mock_db, *_):
worker = Worker('dummy')
worker = Worker('dummy', max_backoff_delay_seconds=60)

self.assertEqual(worker.database, mock_db.return_value)
self.assertEqual(worker.sleep_delay, 10)
Expand Down

0 comments on commit 95eaba5

Please sign in to comment.