def test_find_or_upsert(self): class UpsertTest(ModelBase): table_name = "upserts" attrs = { "name": None, "type": None } def insert(ma, name, type): return ma.insert_model(UpsertTest(name=name, type=type)) def upsert(ma, name, type, assign): with transaction(ma): assign.append(ma.find_or_upsert(UpsertTest, dict(name=name, type=type), comp=dict(name=name), return_status=True)) with get_model_access() as ma1, get_model_access() as ma2: with autocommit(ma1): ma1.execute("drop table if exists upserts") ma1.execute("create table upserts (id serial not null primary key, name text not null unique, type text not null, created_at timestamptz not null default now(), updated_at timestamptz not null default now());") ma1.execute("truncate table upserts") # 1) Two transactions: a) create b) upsert a) commit - check that a and b have same id # 2) Two transactions: a) create b) upsert a) rollback - check that a and b have differnet ids with transaction(ma1): mod1 = insert(ma1, "Trey", "person") mod2a = [] thread1 = Thread(target=lambda: upsert(ma2, "Trey", "person", mod2a)) thread1.start() sleep(0.25) self.assertTrue(thread1.is_alive()) thread1.join() mod2, mod2_status = mod2a[0] self.assertEqual(mod2_status, "duplicate") self.assertEqual(mod1.id, mod2.id) with transaction(ma1): mod3 = insert(ma1, "Julie", "person") mod4a = [] thread2 = Thread(target=lambda: upsert(ma2, "Julie", "person", mod4a)) thread2.start() sleep(0.25) self.assertTrue(thread2.is_alive()) raise RollbackTransaction() thread2.join() mod4, mod4_status = mod4a[0] self.assertEqual(mod4_status, "created") self.assertNotEqual(mod3.id, mod4.id) mod5a = [] upsert(ma1, "Trey", "person", mod5a) mod5, mod5_status = mod5a[0] self.assertEqual(mod5_status, "found") self.assertEqual(mod5.id, mod1.id)
def _start_a_job(self): """Either starts a waiting job and returns a 3-tuple of (job, sz_key, future), or finds no waiting job and returns a 3-tuple of (None, None, None). """ with transaction(self._model_access): (job, sz_key) = self._get_next_job() if job is None: return (None, None, None) job.started_at = utc_now() if sz_key: sz_key.active_job_id = job.id self._update_job(job, sz_key) def fxn(): """Future closure.""" if job.name not in self._job_handlers: raise KeyError("Bad job name") self._job_handlers[job.name](job.payload) future = self._executor.submit(fxn) return (job, sz_key, future)
def test_autocommit_contextmanager(self): da = get_data_access().open(autocommit=False) cnst = dict(first_name=rand(), last_name=rand(), age=3) with transaction(da): with autocommit(da): da.insert("people", cnst) # Rollback should have no effect da.rollback() self.assertEqual(da.find("people", cnst).first_name, cnst["first_name"]) da.delete("people", cnst) da.commit()
def test_transaction_contextmanager(self): da1 = get_data_access().open() da2 = get_data_access().open() da1.autocommit = False cnst = dict(first_name=rand(), last_name=rand(), age=3) with transaction(da1) as da: self.assertIsInstance(da, DataAccess) with transaction(da1): da1.insert("people", cnst) self.assertEqual(da2.find("people", cnst).first_name, cnst["first_name"]) with transaction(da1): da1.delete("people", cnst) da1.autocommit = True self.assertEqual(da1.count("people"), 11) try: with transaction(da1): da1.insert("people", cnst) raise Exception() except Exception as ex: pass finally: self.assertIsNone(da1.find("people", cnst))
def _finished_job(self, job, sz_key, future): """Marks the job as complete. :param job: the Job instance :param sz_key: the SerializationKey instance :param future: the Future instance that handled the job """ error_message = exception_to_message(future.exception()) job.update(completed_at=utc_now(), error_message=error_message) if sz_key: sz_key.active_job_id = None with transaction(self._model_access): self._update_job(job, sz_key)
def _schedule_jobs(self): # Don't schedule jobs if the frequency is None if self._schedule_frequency is None: return None # Only perform a diff check if jobs have been scheduled if self._last_job_scheduling is not None: ts = utc_now().timestamp() # If the last scheduling timestamp plus the frequency is greater than the # current timestamp, it is not yet time to schedule. if self._last_job_scheduling + self._schedule_frequency > ts: return None with transaction(self._model_access): cr, _ = self._model_access.callproc("schedule_jobs", []) job_count = self._model_access.get_scalar(cr) self._last_job_scheduling = utc_now().timestamp() return job_count
def upsert(ma, name, type, assign): with transaction(ma): assign.append(ma.find_or_upsert(UpsertTest, dict(name=name, type=type), comp=dict(name=name), return_status=True))