saq 0.24.6__py3-none-any.whl → 0.24.9__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.6"
17
+ __version__ = "0.24.9"
saq/queue/postgres.py CHANGED
@@ -138,7 +138,6 @@ class PostgresQueue(Queue):
138
138
  self._waiting = 0 # Internal counter of worker tasks waiting for dequeue
139
139
  self._dequeue_conn: AsyncConnection | None = None
140
140
  self._connection_lock = asyncio.Lock()
141
- self._releasing: list[str] = []
142
141
  self._has_sweep_lock = False
143
142
  self._channel = CHANNEL.format(self.name)
144
143
  self._listener = ListenMultiplexer(self.pool, self._channel)
@@ -480,30 +479,34 @@ class PostgresQueue(Queue):
480
479
 
481
480
  job.status = status or job.status
482
481
 
483
- await conn.execute(
484
- SQL(
485
- dedent(
486
- """
487
- UPDATE {jobs_table} SET
488
- job = %(job)s
489
- ,status = %(status)s
490
- ,scheduled = %(scheduled)s
491
- {expire_at}
492
- WHERE key = %(key)s
493
- """
494
- )
495
- ).format(
496
- jobs_table=self.jobs_table,
497
- expire_at=SQL(",expire_at = %(expire_at)s" if expire_at != -1 else ""),
498
- ),
499
- {
500
- "job": self.serialize(job),
501
- "status": job.status,
502
- "key": job.key,
503
- "scheduled": job.scheduled,
504
- "expire_at": expire_at,
505
- },
506
- )
482
+ try:
483
+ await conn.execute(
484
+ SQL(
485
+ dedent(
486
+ """
487
+ UPDATE {jobs_table} SET
488
+ job = %(job)s
489
+ ,status = %(status)s
490
+ ,scheduled = %(scheduled)s
491
+ {expire_at}
492
+ WHERE key = %(key)s
493
+ """
494
+ )
495
+ ).format(
496
+ jobs_table=self.jobs_table,
497
+ expire_at=SQL(",expire_at = %(expire_at)s" if expire_at != -1 else ""),
498
+ ),
499
+ {
500
+ "job": self.serialize(job),
501
+ "status": job.status,
502
+ "key": job.key,
503
+ "scheduled": job.scheduled,
504
+ "expire_at": expire_at,
505
+ },
506
+ )
507
+ finally:
508
+ if job.status != Status.ACTIVE:
509
+ await self._release_job(job.key)
507
510
 
508
511
  async def job(self, job_key: str) -> Job | None:
509
512
  async with self.pool.connection() as conn, conn.cursor() as cursor:
@@ -643,7 +646,7 @@ class PostgresQueue(Queue):
643
646
  dedent(
644
647
  """
645
648
  WITH locked_job AS (
646
- SELECT key, lock_key
649
+ SELECT key
647
650
  FROM {jobs_table}
648
651
  WHERE status = 'queued'
649
652
  AND queue = %(queue)s
@@ -663,13 +666,11 @@ class PostgresQueue(Queue):
663
666
  UPDATE {jobs_table} SET status = 'active'
664
667
  FROM locked_job
665
668
  WHERE {jobs_table}.key = locked_job.key
666
- AND pg_try_advisory_lock({job_lock_keyspace}, locked_job.lock_key)
667
- RETURNING job
669
+ RETURNING job, {jobs_table}.key
668
670
  """
669
671
  )
670
672
  ).format(
671
673
  jobs_table=self.jobs_table,
672
- job_lock_keyspace=self.job_lock_keyspace,
673
674
  ),
674
675
  {
675
676
  "queue": self.name,
@@ -681,8 +682,31 @@ class PostgresQueue(Queue):
681
682
  )
682
683
  results = await cursor.fetchall()
683
684
 
684
- for result in results:
685
- self._job_queue.put_nowait(self.deserialize(result[0]))
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 results]},
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
+ )
707
+
708
+ for job, _ in results:
709
+ self._job_queue.put_nowait(self.deserialize(job))
686
710
 
687
711
  if results:
688
712
  await self._notify(DEQUEUE)
@@ -839,7 +863,7 @@ class PostgresQueue(Queue):
839
863
  ).format(jobs_table=self.jobs_table),
840
864
  {"key": key},
841
865
  )
842
- await self._release_job(key)
866
+ await self._release_job(key)
843
867
 
844
868
  async def _notify(self, key: str, connection: AsyncConnection | None = None) -> None:
845
869
  async with self.nullcontext(connection) if connection else self.pool.connection() as conn:
@@ -871,26 +895,22 @@ class PostgresQueue(Queue):
871
895
  yield enter_result
872
896
 
873
897
  async def _release_job(self, key: str) -> None:
874
- self._releasing.append(key)
875
- if self._connection_lock.locked():
876
- return
877
- async with self._get_dequeue_conn() as conn:
898
+ async with self._get_dequeue_conn() as conn, conn:
878
899
  await conn.execute(
879
900
  SQL(
880
901
  dedent(
881
902
  """
882
903
  SELECT pg_advisory_unlock({job_lock_keyspace}, lock_key)
883
904
  FROM {jobs_table}
884
- WHERE key = ANY(%(keys)s)
905
+ WHERE key = %(key)s
885
906
  """
886
907
  )
887
908
  ).format(
888
909
  jobs_table=self.jobs_table,
889
910
  job_lock_keyspace=self.job_lock_keyspace,
890
911
  ),
891
- {"keys": self._releasing},
912
+ {"key": key},
892
913
  )
893
- self._releasing.clear()
894
914
 
895
915
  @cached_property
896
916
  def _job_queue(self) -> asyncio.Queue:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: saq
3
- Version: 0.24.6
3
+ Version: 0.24.9
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=9-iA2pE4jP5kLkITxQjhBvPZukTSXtSbjaT22sebwnw,218
1
+ saq/__init__.py,sha256=G_2GAPgXY3_BEk5HNQpH8pQf3RqSY6Mjx8ZIOSSTRtc,218
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
@@ -10,7 +10,7 @@ saq/worker.py,sha256=W9rqK_u0bbvUbdb879pvf1f-suNnesKk1TjYqHQREc8,16817
10
10
  saq/queue/__init__.py,sha256=5LgBHGylCVvrLDcjMCcI2dRRgh0BPdz2TKOdc8NMs2E,87
11
11
  saq/queue/base.py,sha256=vRSr4ExGETlkjc9bLrtqfi_A7Zsr_IQzCMyN_b70-UM,15572
12
12
  saq/queue/http.py,sha256=V9S26gJbUt5AUIR2ETasSQy4Q_K30eGtguBYHpfcLGU,7739
13
- saq/queue/postgres.py,sha256=PREn1HBA8E_m57cpdtcBNov1YW8658nR7iESyQ8YHhI,34682
13
+ saq/queue/postgres.py,sha256=R3nQBNWk4rZyAm52lUQyqxl0g37OnGUlL_Ixo9UgV9o,35580
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.6.dist-info/LICENSE,sha256=p208OXrLf_dMcvuRHpcinfsJdihCqKWbqtFXpw4kyW0,1065
24
- saq-0.24.6.dist-info/METADATA,sha256=oJf-Wl30e1v24Nri7koife_X97945RymUfb_g0bPR0I,7781
25
- saq-0.24.6.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
26
- saq-0.24.6.dist-info/entry_points.txt,sha256=HkKOud1K15_DV7AEltn8G5Ua10VqIgHaZ4BQit4fdOk,42
27
- saq-0.24.6.dist-info/top_level.txt,sha256=FMrrc5EiGr4sQkEDtUMHIpomnWHL9i6xT7B6lvEh8xM,4
28
- saq-0.24.6.dist-info/RECORD,,
23
+ saq-0.24.9.dist-info/LICENSE,sha256=p208OXrLf_dMcvuRHpcinfsJdihCqKWbqtFXpw4kyW0,1065
24
+ saq-0.24.9.dist-info/METADATA,sha256=zPpbi2NsgYJVaZJk2TIJm9TVB9M3IZJoinrnV-uekOQ,7781
25
+ saq-0.24.9.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
26
+ saq-0.24.9.dist-info/entry_points.txt,sha256=HkKOud1K15_DV7AEltn8G5Ua10VqIgHaZ4BQit4fdOk,42
27
+ saq-0.24.9.dist-info/top_level.txt,sha256=FMrrc5EiGr4sQkEDtUMHIpomnWHL9i6xT7B6lvEh8xM,4
28
+ saq-0.24.9.dist-info/RECORD,,
File without changes
File without changes