def coordinated_commit(queued_tasks): session = Client().session() try: session.commit() except sqlalchemy.exc.OperationalError as sqlError: # If we've sent tasks to redis but have lost the database, those tasks # probably point to invalid data. They'll likely fail anyway when the # worker can't get the database, and even if they don't, whatever # operation they relate to has been lost. exc_info = sys.exc_info() try: for task in queued_tasks: task.revoke() except (redis.exceptions.ConnectionError, redis.exceptions.TimeoutError) as redisError: # If we've lost the database, redis connection errors seem likely. # Try to report the whole failure. raise SkyIsFallingError(sqlError, redisError), None, exc_info[2] raise sqlError, None, exc_info[2] except (sqlalchemy.exc.DatabaseError, sqlalchemy.exc.StatementError) as sqlError: exc_info = sys.exc_info() try: # If we've sent tasks to redis, they probably point to invalid # data. Even if they don't, whatever operation they relate to was # invalid in some way or another, so this needs to be a # coordinated rollback. coordinated_rollback(queued_tasks) raise sqlError, None, exc_info[2] except (redis.exceptions.ConnectionError, redis.exceptions.TimeoutError) as redisError: raise SkyIsFallingError(sqlError, redisError), 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 = 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()
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 = AssertionError( "Don't try to roll back when the db is unavailable") session.commit = Mock() session.commit.side_effect = \ OperationalError(None, None, b'database timeout') assert_raises(SkyIsFallingError, lambda: coordinated_commit([task])) task.revoke.assert_called_once_with()
session = Client().session() metadata = MetaData(bind=Client()._engine) temp_image_tag = Table( 'temp_image_tags', metadata, Column('tag_name', String, primary_key=True), Column('filename', String, primary_key=True), prefixes=['temporary'], ) metadata.create_all() session.execute(temp_image_tag.insert(image_tags)) session.execute(Image.__table__.insert(images)) session.execute(Tag.__table__.insert(tags)) #I can't figure out how to make sqlalchemy generate this query! :( session.execute(""" insert into image_tag (image_id, tag_id) ( select image.image_id, tag.tag_id from temp_image_tags inner join image using (filename) inner join tag on tag.name = temp_image_tags.tag_name ) """) session.commit()