saq 0.24.8__py3-none-any.whl → 0.24.10__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
saq/__init__.py CHANGED
@@ -14,4 +14,4 @@ __all__ = [
14
14
  "Worker",
15
15
  ]
16
16
 
17
- __version__ = "0.24.8"
17
+ __version__ = "0.24.10"
saq/queue/base.py CHANGED
@@ -219,13 +219,18 @@ class Queue(ABC):
219
219
  def serialize(self, job: Job) -> bytes | str:
220
220
  return self._dump(job.to_dict())
221
221
 
222
- def deserialize(self, payload: dict | str | bytes | None) -> Job | None:
222
+ def deserialize(
223
+ self, payload: dict | str | bytes | None, status: Status | str | None = None
224
+ ) -> Job | None:
223
225
  if not payload:
224
226
  return None
225
227
 
226
228
  job_dict = payload if isinstance(payload, dict) else self._load(payload)
227
229
  if job_dict.pop("queue") != self.name:
228
230
  raise ValueError(f"Job {job_dict} fetched by wrong queue: {self.name}")
231
+
232
+ if status:
233
+ job_dict["status"] = status
229
234
  return Job(**job_dict, queue=self)
230
235
 
231
236
  async def worker_info(
saq/queue/postgres.py CHANGED
@@ -260,14 +260,14 @@ class PostgresQueue(Queue):
260
260
  ).format(stats_table=self.stats_table),
261
261
  {"queue": self.name},
262
262
  )
263
- results = await cursor.fetchall()
263
+ rows = await cursor.fetchall()
264
264
  workers: dict[str, WorkerInfo] = {
265
265
  worker_id: {
266
266
  "stats": stats,
267
267
  "metadata": metadata,
268
268
  "queue_key": queue_key,
269
269
  }
270
- for worker_id, stats, queue_key, metadata in results
270
+ for worker_id, stats, queue_key, metadata in rows
271
271
  }
272
272
 
273
273
  queued = await self.count("queued")
@@ -280,7 +280,7 @@ class PostgresQueue(Queue):
280
280
  SQL(
281
281
  dedent(
282
282
  """
283
- SELECT job FROM {jobs_table}
283
+ SELECT job, status FROM {jobs_table}
284
284
  WHERE status IN ('new', 'deferred', 'queued', 'active')
285
285
  AND queue = %(queue)s
286
286
  """
@@ -288,8 +288,8 @@ class PostgresQueue(Queue):
288
288
  ).format(jobs_table=self.jobs_table),
289
289
  {"queue": self.name},
290
290
  )
291
- results = await cursor.fetchall()
292
- deserialized_jobs = (self.deserialize(result[0]) for result in results)
291
+ rows = await cursor.fetchall()
292
+ deserialized_jobs = (self.deserialize(*row) for row in rows)
293
293
  jobs_info = [job.to_dict() for job in deserialized_jobs if job]
294
294
  else:
295
295
  jobs_info = []
@@ -441,10 +441,10 @@ class PostgresQueue(Queue):
441
441
  "job_lock_keyspace": self.job_lock_keyspace,
442
442
  },
443
443
  )
444
- results = await cursor.fetchall()
444
+ rows = await cursor.fetchall()
445
445
 
446
- for key, job_bytes, objid, status in results:
447
- job = self.deserialize(job_bytes)
446
+ for key, job_bytes, objid, status in rows:
447
+ job = self.deserialize(job_bytes, status)
448
448
  assert job
449
449
  if (objid or not self.job_lock_sweep) and not job.stuck:
450
450
  continue
@@ -514,7 +514,7 @@ class PostgresQueue(Queue):
514
514
  SQL(
515
515
  dedent(
516
516
  """
517
- SELECT job
517
+ SELECT job, status
518
518
  FROM {jobs_table}
519
519
  WHERE key = %(key)s AND queue = %(queue)s
520
520
  """
@@ -522,9 +522,9 @@ class PostgresQueue(Queue):
522
522
  ).format(jobs_table=self.jobs_table),
523
523
  {"key": job_key, "queue": self.name},
524
524
  )
525
- job = await cursor.fetchone()
526
- if job:
527
- return self.deserialize(job[0])
525
+ row = await cursor.fetchone()
526
+ if row:
527
+ return self.deserialize(*row)
528
528
  return None
529
529
 
530
530
  async def jobs(self, job_keys: Iterable[str]) -> t.List[Job | None]:
@@ -535,7 +535,7 @@ class PostgresQueue(Queue):
535
535
  SQL(
536
536
  dedent(
537
537
  """
538
- SELECT key, job
538
+ SELECT key, job, status
539
539
  FROM {jobs_table}
540
540
  WHERE key = ANY(%(keys)s)
541
541
  """
@@ -543,8 +543,8 @@ class PostgresQueue(Queue):
543
543
  ).format(jobs_table=self.jobs_table),
544
544
  {"keys": keys},
545
545
  )
546
- results: dict[str, bytes | None] = dict(await cursor.fetchall())
547
- return [self.deserialize(results.get(key)) for key in keys]
546
+ results = {r[0]: r[1:] for r in await cursor.fetchall()}
547
+ return [self.deserialize(*(results.get(key) or [None])) for key in keys]
548
548
 
549
549
  async def iter_jobs(
550
550
  self,
@@ -559,7 +559,7 @@ class PostgresQueue(Queue):
559
559
  SQL(
560
560
  dedent(
561
561
  """
562
- SELECT key, job
562
+ SELECT key, job, status
563
563
  FROM {jobs_table}
564
564
  WHERE
565
565
  status = ANY(%(statuses)s)
@@ -581,9 +581,9 @@ class PostgresQueue(Queue):
581
581
  rows = await cursor.fetchall()
582
582
 
583
583
  if rows:
584
- for key, job_bytes in rows:
584
+ for key, job_bytes, status in rows:
585
585
  last_key = key
586
- job = self.deserialize(job_bytes)
586
+ job = self.deserialize(job_bytes, status)
587
587
  if job:
588
588
  yield job
589
589
  else:
@@ -638,7 +638,7 @@ class PostgresQueue(Queue):
638
638
  return
639
639
 
640
640
  async with self._dequeue_lock:
641
- async with self._get_dequeue_conn() as conn, conn.cursor() as cursor:
641
+ async with self._get_dequeue_conn() as conn, conn.transaction(), conn.cursor() as cursor:
642
642
  if not self._waiting:
643
643
  return
644
644
  await cursor.execute(
@@ -659,7 +659,6 @@ class PostgresQueue(Queue):
659
659
  AND queue = %(queue)s
660
660
  AND group_key IS NOT NULL
661
661
  )
662
- AND pg_try_advisory_lock({job_lock_keyspace}, lock_key)
663
662
  ORDER BY priority, scheduled
664
663
  LIMIT %(limit)s
665
664
  FOR UPDATE SKIP LOCKED
@@ -667,12 +666,11 @@ class PostgresQueue(Queue):
667
666
  UPDATE {jobs_table} SET status = 'active'
668
667
  FROM locked_job
669
668
  WHERE {jobs_table}.key = locked_job.key
670
- RETURNING job
669
+ RETURNING job, {jobs_table}.key, status
671
670
  """
672
671
  )
673
672
  ).format(
674
673
  jobs_table=self.jobs_table,
675
- job_lock_keyspace=self.job_lock_keyspace,
676
674
  ),
677
675
  {
678
676
  "queue": self.name,
@@ -682,12 +680,35 @@ class PostgresQueue(Queue):
682
680
  "phigh": self._priorities[1],
683
681
  },
684
682
  )
685
- results = await cursor.fetchall()
683
+ rows = await cursor.fetchall()
684
+
685
+ await conn.execute(
686
+ SQL(
687
+ dedent(
688
+ """
689
+ SELECT key, pg_try_advisory_lock({job_lock_keyspace}, lock_key)
690
+ FROM {jobs_table}
691
+ WHERE key = ANY(%(keys)s)
692
+ """
693
+ )
694
+ ).format(
695
+ jobs_table=self.jobs_table,
696
+ job_lock_keyspace=self.job_lock_keyspace,
697
+ ),
698
+ {"keys": [key for _, key, _ in rows]},
699
+ )
700
+ lock_acquisition_results = await cursor.fetchall()
701
+ for key, lock_acquired in lock_acquisition_results:
702
+ if not lock_acquired:
703
+ logger.error(
704
+ "Could not acquire lock for job %s. This may result in unexpected behavior",
705
+ key,
706
+ )
686
707
 
687
- for result in results:
688
- self._job_queue.put_nowait(self.deserialize(result[0]))
708
+ for job, _, status in rows:
709
+ self._job_queue.put_nowait(self.deserialize(job, status))
689
710
 
690
- if results:
711
+ if rows:
691
712
  await self._notify(DEQUEUE)
692
713
 
693
714
  async def _enqueue(self, job: Job) -> Job | None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: saq
3
- Version: 0.24.8
3
+ Version: 0.24.10
4
4
  Summary: Distributed Python job queue with asyncio and redis
5
5
  Home-page: https://github.com/tobymao/saq
6
6
  Author: Toby Mao
@@ -1,4 +1,4 @@
1
- saq/__init__.py,sha256=8Yq6PVEa09HJzvRvQV0TUGSmOPqkdsJfNGYooR-DZ10,218
1
+ saq/__init__.py,sha256=vYIFEVix-39RzyynnCqMQVZMrhIr4ns1aeJOmEXWCt0,219
2
2
  saq/__main__.py,sha256=N4RNqnCcj7eZbM3OyYaC03_6Cot-y-SxW5Hwx6fuzKU,2440
3
3
  saq/errors.py,sha256=XPJw6J3caSAho4ZybuodIbeuGjboVabLuf3NFOEE-4Q,112
4
4
  saq/job.py,sha256=X49OuSqZeN-RVmh4AonZRrwk2wU8MeukLSxrvjGLm7E,11552
@@ -8,9 +8,9 @@ saq/types.py,sha256=GhIq2BIE_Z9hA-qS-NQXh_iPICNI0NZxOzjW0vcMgFU,3196
8
8
  saq/utils.py,sha256=NdOycT-03zxjhKM8A1i0vzKnkv1UQxvy_Zt4GnO0Zd8,1721
9
9
  saq/worker.py,sha256=W9rqK_u0bbvUbdb879pvf1f-suNnesKk1TjYqHQREc8,16817
10
10
  saq/queue/__init__.py,sha256=5LgBHGylCVvrLDcjMCcI2dRRgh0BPdz2TKOdc8NMs2E,87
11
- saq/queue/base.py,sha256=vRSr4ExGETlkjc9bLrtqfi_A7Zsr_IQzCMyN_b70-UM,15572
11
+ saq/queue/base.py,sha256=wej8WBWK-S9GXYEHXTfl7Wwwm-DB3o1RB-bHMvNLfdI,15682
12
12
  saq/queue/http.py,sha256=V9S26gJbUt5AUIR2ETasSQy4Q_K30eGtguBYHpfcLGU,7739
13
- saq/queue/postgres.py,sha256=Zb59GWPy36K6FaW3atdYOl4KBykoFVkW8S3gwX59nAc,34719
13
+ saq/queue/postgres.py,sha256=7FSljVrqISV8w82cv0yWvyejMpucbucsjpu8Ntoqee4,35648
14
14
  saq/queue/postgres_migrations.py,sha256=gI6j-0TzlFFSWxji3Dy9aJ-llboJBm92J4tB_YZ7qI8,2080
15
15
  saq/queue/redis.py,sha256=sa_wzUUlfPw-RZ-v_cnDEJWEFyUi3sy_3YTqG4UklOA,17754
16
16
  saq/web/__init__.py,sha256=NG9LfjgJQxNft0_iZuZ3LnX1I58SfxRwKpycjazBoGE,23
@@ -20,9 +20,9 @@ saq/web/starlette.py,sha256=i38xuNcnQvWBY3jyHHu9Uo9ILSBzOwmk5Bq06c3CQzM,4432
20
20
  saq/web/static/app.js,sha256=i6PaRvBvt96LOINBdEuKkDvVeM-GA8lJiFg4jtQ3viY,7094
21
21
  saq/web/static/pico.min.css.gz,sha256=qCxIv3wWFMQ7MkvGSHQLwxio3121VvvieOkSjw6fv6o,9263
22
22
  saq/web/static/snabbdom.js.gz,sha256=zSO3Z761TB7bYNQFFEtypD0vCuqWesqPJeE5CuV4xRg,7603
23
- saq-0.24.8.dist-info/LICENSE,sha256=p208OXrLf_dMcvuRHpcinfsJdihCqKWbqtFXpw4kyW0,1065
24
- saq-0.24.8.dist-info/METADATA,sha256=SlpZba2Kq2khnXyF5ik6kjBzcY5FqwypKbn91EbrTSM,7781
25
- saq-0.24.8.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
26
- saq-0.24.8.dist-info/entry_points.txt,sha256=HkKOud1K15_DV7AEltn8G5Ua10VqIgHaZ4BQit4fdOk,42
27
- saq-0.24.8.dist-info/top_level.txt,sha256=FMrrc5EiGr4sQkEDtUMHIpomnWHL9i6xT7B6lvEh8xM,4
28
- saq-0.24.8.dist-info/RECORD,,
23
+ saq-0.24.10.dist-info/LICENSE,sha256=p208OXrLf_dMcvuRHpcinfsJdihCqKWbqtFXpw4kyW0,1065
24
+ saq-0.24.10.dist-info/METADATA,sha256=iPnYOcZctuzl-5KOEWq7UoOBSexbYKFTtBvEM_KUr40,7782
25
+ saq-0.24.10.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
26
+ saq-0.24.10.dist-info/entry_points.txt,sha256=HkKOud1K15_DV7AEltn8G5Ua10VqIgHaZ4BQit4fdOk,42
27
+ saq-0.24.10.dist-info/top_level.txt,sha256=FMrrc5EiGr4sQkEDtUMHIpomnWHL9i6xT7B6lvEh8xM,4
28
+ saq-0.24.10.dist-info/RECORD,,
File without changes
File without changes