labtasker-server 2.0.0__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.
- labtasker_server/__init__.py +3 -0
- labtasker_server/__main__.py +3 -0
- labtasker_server/app.py +416 -0
- labtasker_server/cli.py +371 -0
- labtasker_server/config.py +42 -0
- labtasker_server/database.py +176 -0
- labtasker_server/errors.py +27 -0
- labtasker_server/filtering.py +528 -0
- labtasker_server/local.py +453 -0
- labtasker_server/logging.py +47 -0
- labtasker_server/middleware.py +73 -0
- labtasker_server/migrations/__init__.py +1 -0
- labtasker_server/migrations/env.py +20 -0
- labtasker_server/migrations/versions/0001_initial.py +135 -0
- labtasker_server/migrations/versions/__init__.py +1 -0
- labtasker_server/models.py +139 -0
- labtasker_server/pagination.py +126 -0
- labtasker_server/py.typed +1 -0
- labtasker_server/schemas.py +265 -0
- labtasker_server/services/__init__.py +1 -0
- labtasker_server/services/queues.py +66 -0
- labtasker_server/services/tasks.py +859 -0
- labtasker_server/validation.py +150 -0
- labtasker_server-2.0.0.dist-info/METADATA +16 -0
- labtasker_server-2.0.0.dist-info/RECORD +28 -0
- labtasker_server-2.0.0.dist-info/WHEEL +4 -0
- labtasker_server-2.0.0.dist-info/entry_points.txt +2 -0
- labtasker_server-2.0.0.dist-info/licenses/LICENSE +201 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from sqlalchemy import func, select
|
|
4
|
+
|
|
5
|
+
from labtasker_server.database import Database
|
|
6
|
+
from labtasker_server.errors import conflict, not_found
|
|
7
|
+
from labtasker_server.models import QueueRow, TaskRow
|
|
8
|
+
from labtasker_server.schemas import Queue
|
|
9
|
+
from labtasker_server.validation import validate_identifier
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class QueueService:
|
|
13
|
+
def __init__(self, database: Database) -> None:
|
|
14
|
+
self.database = database
|
|
15
|
+
|
|
16
|
+
def create(self, name: str) -> tuple[Queue, bool]:
|
|
17
|
+
name = validate_identifier(name, kind="Queue")
|
|
18
|
+
with self.database.write_session() as session:
|
|
19
|
+
existing = session.get(QueueRow, name)
|
|
20
|
+
if existing is not None:
|
|
21
|
+
return Queue(name=existing.name), False
|
|
22
|
+
row = QueueRow(name=name)
|
|
23
|
+
session.add(row)
|
|
24
|
+
session.flush()
|
|
25
|
+
return Queue(name=row.name), True
|
|
26
|
+
|
|
27
|
+
def list(self) -> list[Queue]:
|
|
28
|
+
with self.database.read_session() as session:
|
|
29
|
+
names = session.scalars(select(QueueRow.name).order_by(QueueRow.name)).all()
|
|
30
|
+
return [Queue(name=name) for name in names]
|
|
31
|
+
|
|
32
|
+
def require_exists(self, name: str) -> None:
|
|
33
|
+
name = validate_identifier(name, kind="Queue")
|
|
34
|
+
with self.database.read_session() as session:
|
|
35
|
+
if session.get(QueueRow, name) is None:
|
|
36
|
+
raise not_found("queue_not_found", "Queue does not exist.", queue=name)
|
|
37
|
+
|
|
38
|
+
def delete(self, name: str, *, cascade: bool) -> None:
|
|
39
|
+
name = validate_identifier(name, kind="Queue")
|
|
40
|
+
with self.database.write_session() as session:
|
|
41
|
+
row = session.get(QueueRow, name)
|
|
42
|
+
if row is None:
|
|
43
|
+
raise not_found("queue_not_found", "Queue does not exist.", queue=name)
|
|
44
|
+
running = session.scalar(
|
|
45
|
+
select(func.count())
|
|
46
|
+
.select_from(TaskRow)
|
|
47
|
+
.where(TaskRow.queue_name == name, TaskRow.status == "running")
|
|
48
|
+
)
|
|
49
|
+
if running:
|
|
50
|
+
raise conflict(
|
|
51
|
+
"queue_has_running_tasks",
|
|
52
|
+
"Queue contains running Tasks; cancel them before deletion.",
|
|
53
|
+
queue=name,
|
|
54
|
+
running=running,
|
|
55
|
+
)
|
|
56
|
+
task_count = session.scalar(
|
|
57
|
+
select(func.count()).select_from(TaskRow).where(TaskRow.queue_name == name)
|
|
58
|
+
)
|
|
59
|
+
if task_count and not cascade:
|
|
60
|
+
raise conflict(
|
|
61
|
+
"queue_not_empty",
|
|
62
|
+
"Queue is not empty; use cascade to delete its Tasks.",
|
|
63
|
+
queue=name,
|
|
64
|
+
tasks=task_count,
|
|
65
|
+
)
|
|
66
|
+
session.delete(row)
|