def __contains__(self, key): """return True if we have a job by this key""" try: with transaction_context(self.database_class) as conn: single_value_sql( conn, """SELECT app_name FROM cron_job WHERE app_name = %s""", (key, )) return True except SQLDidNotReturnSingleValue: return False
def test_single_value_sql2(self): m_execute = Mock() m_fetchall = Mock(return_value=((17,),)) m_cursor = MagicMock() m_cursor.execute = m_execute m_cursor.fetchall = m_fetchall conn = MagicMock() conn.cursor.return_value.__enter__.return_value = m_cursor dbutil.single_value_sql(conn, "select 17", (1, 2, 3)) assert conn.cursor.call_count == 1 assert m_cursor.execute.call_count == 1 m_cursor.execute.assert_called_once_with('select 17', (1, 2, 3))
def __contains__(self, key): """return True if we have a job by this key""" try: with transaction_context(self.database_class) as conn: single_value_sql( conn, """SELECT app_name FROM cron_job WHERE app_name = %s""", (key,) ) return True except SQLDidNotReturnSingleValue: return False
def test_single_value_sql3(self): m_execute = Mock() m_fetchall = Mock(return_value=None) m_cursor = MagicMock() m_cursor.execute = m_execute m_cursor.fetchall = m_fetchall conn = MagicMock() conn.cursor.return_value.__enter__.return_value = m_cursor with pytest.raises(dbutil.SQLDidNotReturnSingleValue): dbutil.single_value_sql(conn, 'select 17', (1, 2, 3)) assert conn.cursor.call_count == 1 assert m_cursor.execute.call_count == 1 m_cursor.execute.assert_called_once_with('select 17', (1, 2, 3))
def __delitem__(self, key): """remove the item by key or raise KeyError""" with transaction_context(self.database_class) as connection: try: # result intentionally ignored single_value_sql( connection, """SELECT app_name FROM cron_job WHERE app_name = %s""", (key, )) except SQLDidNotReturnSingleValue: raise KeyError(key) # item exists execute_no_results( connection, """DELETE FROM cron_job WHERE app_name = %s""", (key, ))
def __delitem__(self, key): """remove the item by key or raise KeyError""" with transaction_context(self.database_class) as connection: try: # result intentionally ignored single_value_sql( connection, """SELECT app_name FROM cron_job WHERE app_name = %s""", (key,) ) except SQLDidNotReturnSingleValue: raise KeyError(key) # item exists execute_no_results( connection, """DELETE FROM cron_job WHERE app_name = %s""", (key,) )
def __setitem__(self, key, value): class LastErrorEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, type): return repr(obj) return json.JSONEncoder.default(self, obj) with transaction_context(self.database_class) as connection: try: single_value_sql( connection, """ SELECT ongoing FROM cron_job WHERE app_name = %s FOR UPDATE NOWAIT """, (key, )) # If the above single_value_sql() didn't raise a # SQLDidNotReturnSingleValue exception, it means # there is a row by this app_name. # Therefore, the next SQL is an update. next_sql = """ UPDATE cron_job SET next_run = %(next_run)s, first_run = %(first_run)s, last_run = %(last_run)s, last_success = %(last_success)s, depends_on = %(depends_on)s, error_count = %(error_count)s, last_error = %(last_error)s, ongoing = %(ongoing)s WHERE app_name = %(app_name)s """ except OperationalError as exception: if 'could not obtain lock' in exception.args[0]: raise RowLevelLockError(exception.args[0]) else: raise except SQLDidNotReturnSingleValue: # the key does not exist, do an insert next_sql = """ INSERT INTO cron_job ( app_name, next_run, first_run, last_run, last_success, depends_on, error_count, last_error, ongoing ) VALUES ( %(app_name)s, %(next_run)s, %(first_run)s, %(last_run)s, %(last_success)s, %(depends_on)s, %(error_count)s, %(last_error)s, %(ongoing)s ) """ # serialize last_error if it's a {} last_error = value['last_error'] if isinstance(last_error, dict): last_error = json.dumps(value['last_error'], cls=LastErrorEncoder) parameters = { 'app_name': key, 'next_run': value['next_run'], 'first_run': value['first_run'], 'last_run': value['last_run'], 'last_success': value.get('last_success'), 'depends_on': value['depends_on'], 'error_count': value['error_count'], 'last_error': last_error, 'ongoing': value.get('ongoing'), } try: execute_no_results(connection, next_sql, parameters) except IntegrityError as exception: # See CREATE_CRONTABBER_APP_NAME_UNIQUE_INDEX for why # we know to look for this mentioned in the error message. if 'crontabber_unique_app_name_idx' in exception.args[0]: raise RowLevelLockError(exception.args[0]) raise
def has_data(self): with transaction_context(self.database_class) as conn: return bool(single_value_sql(conn, 'SELECT count(*) FROM cron_job'))
def __setitem__(self, key, value): class LastErrorEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, type): return repr(obj) return json.JSONEncoder.default(self, obj) with transaction_context(self.database_class) as connection: try: single_value_sql( connection, """ SELECT ongoing FROM cron_job WHERE app_name = %s FOR UPDATE NOWAIT """, (key,) ) # If the above single_value_sql() didn't raise a # SQLDidNotReturnSingleValue exception, it means # there is a row by this app_name. # Therefore, the next SQL is an update. next_sql = """ UPDATE cron_job SET next_run = %(next_run)s, first_run = %(first_run)s, last_run = %(last_run)s, last_success = %(last_success)s, depends_on = %(depends_on)s, error_count = %(error_count)s, last_error = %(last_error)s, ongoing = %(ongoing)s WHERE app_name = %(app_name)s """ except OperationalError as exception: if 'could not obtain lock' in exception.args[0]: raise RowLevelLockError(exception.args[0]) else: raise except SQLDidNotReturnSingleValue: # the key does not exist, do an insert next_sql = """ INSERT INTO cron_job ( app_name, next_run, first_run, last_run, last_success, depends_on, error_count, last_error, ongoing ) VALUES ( %(app_name)s, %(next_run)s, %(first_run)s, %(last_run)s, %(last_success)s, %(depends_on)s, %(error_count)s, %(last_error)s, %(ongoing)s ) """ # serialize last_error if it's a {} last_error = value['last_error'] if isinstance(last_error, dict): last_error = json.dumps(value['last_error'], cls=LastErrorEncoder) parameters = { 'app_name': key, 'next_run': value['next_run'], 'first_run': value['first_run'], 'last_run': value['last_run'], 'last_success': value.get('last_success'), 'depends_on': value['depends_on'], 'error_count': value['error_count'], 'last_error': last_error, 'ongoing': value.get('ongoing'), } try: execute_no_results(connection, next_sql, parameters) except IntegrityError as exception: # See CREATE_CRONTABBER_APP_NAME_UNIQUE_INDEX for why # we know to look for this mentioned in the error message. if 'crontabber_unique_app_name_idx' in exception.args[0]: raise RowLevelLockError(exception.args[0]) raise