def run(self, image_id, suffix=None): session = Client().session() now = time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime()) try: image = session.query(Image).\ filter((Image.created_at - timedelta(hours=1)) < now).\ filter(Image.image_id == image_id).\ one() except NoResultFound: session.rollback() logger.error('No unexpired result found for image_id {0}. ' 'Skipping.'.format(image_id)) return filename = image.filename print repr(suffix) if suffix is not None: filename = '{0}_{1}'.format(filename, suffix) config = Client().config() try: distro_id = config['aws.cloudfront_distribution_id'] Client().get_cloudfront().create_invalidation_request( distro_id, [filename]) except KeyError: pass except CloudFrontServerError as e: if e.error_code == 'TooManyInvalidationsInProgress': self.retry(exc=e) else: raise
def test_revokes_tasks_and_rolls_back_in_the_happy_case(self): session = Client().session() task = Mock() with session_cleanup(): session.rollback = Mock() coordinated_rollback([task]) session.rollback.assert_called_once_with() task.revoke.assert_called_once_with()
def coordinated_rollback(queued_tasks): session = Client().session() try: session.rollback() for task in queued_tasks: task.revoke() except sqlalchemy.exc.OperationalError as sqlError: exc_info = sys.exc_info() try: # Still try to revoke all queued tasks even though the database is # down. If this fails too, it'll raise SkyIsFalling; if it # succeeds it'll reraise the sqlError. for task in queued_tasks: task.revoke() except (redis.exceptions.ConnectionError, redis.exceptions.TimeoutError) as redisError: raise SkyIsFallingError(sqlError, redisError), None, exc_info[2] raise sqlError, None, exc_info[2]
def session_cleanup(): session = Client().session() commit = session.commit rollback = session.rollback flush = session.flush try: yield finally: session.commit = commit session.rollback = rollback session.flush = flush
def test_commits_in_the_happy_case(self): session = Client().session() task = Mock() with session_cleanup(): session.commit = Mock() session.rollback = Mock() session.rollback.side_effect = \ AssertionError("Shouldn't've been called") coordinated_commit([task]) session.commit.assert_called_once_with()
def test_revokes_tasks_on_connection_error(self): session = Client().session() task = Mock() with session_cleanup(): session.rollback = Mock() session.rollback.side_effect = \ OperationalError(None, None, 'database timeout') assert_raises(OperationalError, lambda: coordinated_rollback([task])) task.revoke.assert_called_once_with()
def test_revokes_tasks_and_rolls_back_on_data_error(self): session = Client().session() # invalid foreign keys ahoy! session.add(ImageTag(image_id=8675309, tag_id=8675309)) task = Mock() with session_cleanup(): session.rollback = Mock() assert_raises(IntegrityError, lambda: coordinated_commit([task])) session.rollback.assert_called_once_with() task.revoke.assert_called_once_with()
def test_sky_is_falling_if_database_and_redis_are_unreachable(self): session = Client().session() task = Mock() task.revoke.side_effect = TimeoutError('go sit in the corner') with session_cleanup(): session.rollback = Mock() session.rollback.side_effect = \ OperationalError(None, None, b'database timeout') assert_raises(SkyIsFallingError, lambda: coordinated_rollback([task])) task.revoke.assert_called_once_with()
def test_revokes_tasks_on_connection_error(self): session = Client().session() task = Mock() with session_cleanup(): session.rollback = Mock() session.rollback.side_effect = AssertionError( "Don't try to roll back when the db is unavailable") session.commit = Mock() session.commit.side_effect = \ OperationalError(None, None, 'database timeout') assert_raises(OperationalError, lambda: coordinated_commit([task])) task.revoke.assert_called_once_with()