generated from john/python-template
Jobs: big jobs stuck in queue. Added Cancel, Resubmit
This commit is contained in:
@@ -13,6 +13,8 @@ from transcription.db.models import JobStatus
|
||||
from transcription.db.models import Source
|
||||
from transcription.services.documents import DocumentService
|
||||
from transcription.services.jobs import JobDeleteBlockedError
|
||||
from transcription.services.jobs import JobCancelBlockedError
|
||||
from transcription.services.jobs import JobResubmitBlockedError
|
||||
from transcription.services.jobs import JobService
|
||||
|
||||
|
||||
@@ -224,3 +226,157 @@ class TestJobService:
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
await job_service.read_job(job_id=job.id)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_cancel_job_marks_non_transcribed_sources_failed(
|
||||
self,
|
||||
job_service: JobService,
|
||||
document_service: DocumentService,
|
||||
):
|
||||
document = Document(id=uuid4(), name="cancel-job-doc")
|
||||
await document_service.create_document(document=document)
|
||||
|
||||
job = Job(document_id=document.id, status=JobStatus.QUEUED)
|
||||
await job_service.create_job(job=job)
|
||||
|
||||
async with job_service._session_scope() as session:
|
||||
source_one = Source(
|
||||
document_id=document.id,
|
||||
page_number=1,
|
||||
upload_name="cancel-1.jpg",
|
||||
filename="stored-cancel-1.jpg",
|
||||
file_path="/uploads/stored-cancel-1.jpg",
|
||||
)
|
||||
source_two = Source(
|
||||
document_id=document.id,
|
||||
page_number=2,
|
||||
upload_name="cancel-2.jpg",
|
||||
filename="stored-cancel-2.jpg",
|
||||
file_path="/uploads/stored-cancel-2.jpg",
|
||||
)
|
||||
session.add(source_one)
|
||||
session.add(source_two)
|
||||
await session.flush()
|
||||
|
||||
session.add(
|
||||
JobSource(
|
||||
job_id=job.id,
|
||||
source_id=source_one.id,
|
||||
status=JobSourceStatus.TRANSCRIBED,
|
||||
raw_transcription="done",
|
||||
)
|
||||
)
|
||||
session.add(
|
||||
JobSource(
|
||||
job_id=job.id,
|
||||
source_id=source_two.id,
|
||||
status=JobSourceStatus.PENDING,
|
||||
)
|
||||
)
|
||||
await session.commit()
|
||||
|
||||
cancelled = await job_service.cancel_job(job_id=job.id)
|
||||
assert cancelled.status == JobStatus.FAILED
|
||||
|
||||
refreshed = await job_service.read_job(job_id=job.id)
|
||||
statuses = {item.status for item in refreshed.job_sources}
|
||||
assert JobSourceStatus.TRANSCRIBED in statuses
|
||||
assert JobSourceStatus.FAILED in statuses
|
||||
pending_entry = next(item for item in refreshed.job_sources if item.status == JobSourceStatus.FAILED)
|
||||
assert pending_entry.error_detail == "Cancelled by user"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_resubmit_non_transcribed_sources_resets_only_non_transcribed(
|
||||
self,
|
||||
job_service: JobService,
|
||||
document_service: DocumentService,
|
||||
):
|
||||
document = Document(id=uuid4(), name="resubmit-job-doc")
|
||||
await document_service.create_document(document=document)
|
||||
|
||||
job = Job(document_id=document.id, status=JobStatus.FAILED)
|
||||
await job_service.create_job(job=job)
|
||||
|
||||
async with job_service._session_scope() as session:
|
||||
source_one = Source(
|
||||
document_id=document.id,
|
||||
page_number=1,
|
||||
upload_name="resubmit-1.jpg",
|
||||
filename="stored-resubmit-1.jpg",
|
||||
file_path="/uploads/stored-resubmit-1.jpg",
|
||||
raw_transcription="existing text",
|
||||
)
|
||||
source_two = Source(
|
||||
document_id=document.id,
|
||||
page_number=2,
|
||||
upload_name="resubmit-2.jpg",
|
||||
filename="stored-resubmit-2.jpg",
|
||||
file_path="/uploads/stored-resubmit-2.jpg",
|
||||
raw_transcription="done text",
|
||||
)
|
||||
session.add(source_one)
|
||||
session.add(source_two)
|
||||
await session.flush()
|
||||
|
||||
session.add(
|
||||
JobSource(
|
||||
job_id=job.id,
|
||||
source_id=source_one.id,
|
||||
status=JobSourceStatus.FAILED,
|
||||
raw_transcription=None,
|
||||
error_detail="prior error",
|
||||
)
|
||||
)
|
||||
session.add(
|
||||
JobSource(
|
||||
job_id=job.id,
|
||||
source_id=source_two.id,
|
||||
status=JobSourceStatus.TRANSCRIBED,
|
||||
raw_transcription="done text",
|
||||
)
|
||||
)
|
||||
await session.commit()
|
||||
|
||||
count = await job_service.resubmit_non_transcribed_sources(job_id=job.id)
|
||||
assert count == 1
|
||||
|
||||
refreshed = await job_service.read_job(job_id=job.id)
|
||||
assert refreshed.status == JobStatus.QUEUED
|
||||
|
||||
failed_entry = next(item for item in refreshed.job_sources if item.source is not None and item.source.page_number == 1)
|
||||
transcribed_entry = next(item for item in refreshed.job_sources if item.source is not None and item.source.page_number == 2)
|
||||
assert failed_entry.status == JobSourceStatus.PENDING
|
||||
assert failed_entry.error_detail is None
|
||||
assert failed_entry.source is not None
|
||||
assert failed_entry.source.raw_transcription is None
|
||||
assert transcribed_entry.status == JobSourceStatus.TRANSCRIBED
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_resubmit_non_transcribed_sources_blocks_when_processing(
|
||||
self,
|
||||
job_service: JobService,
|
||||
document_service: DocumentService,
|
||||
):
|
||||
document = Document(id=uuid4(), name="resubmit-blocked-doc")
|
||||
await document_service.create_document(document=document)
|
||||
|
||||
job = Job(document_id=document.id, status=JobStatus.PROCESSING)
|
||||
await job_service.create_job(job=job)
|
||||
|
||||
with pytest.raises(JobResubmitBlockedError):
|
||||
await job_service.resubmit_non_transcribed_sources(job_id=job.id)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_cancel_job_blocks_transcribed_terminal_jobs(
|
||||
self,
|
||||
job_service: JobService,
|
||||
document_service: DocumentService,
|
||||
):
|
||||
document = Document(id=uuid4(), name="cancel-blocked-doc")
|
||||
await document_service.create_document(document=document)
|
||||
|
||||
job = Job(document_id=document.id, status=JobStatus.TRANSCRIBED)
|
||||
await job_service.create_job(job=job)
|
||||
|
||||
with pytest.raises(JobCancelBlockedError):
|
||||
await job_service.cancel_job(job_id=job.id)
|
||||
|
||||
@@ -154,3 +154,54 @@ class TestTranscriptionServiceRevisionUpsert:
|
||||
|
||||
with pytest.raises(SourceDeleteBlockedError):
|
||||
await transcriptions.delete_source_from_job_context(job_id=job_one.id, source_id=source.id)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_delete_unlinked_source_succeeds(self, default_session_factory):
|
||||
documents = DocumentService(session_factory=default_session_factory)
|
||||
transcriptions = TranscriptionService(session_factory=default_session_factory)
|
||||
|
||||
document = Document(id=uuid4(), name="delete-unlinked-source")
|
||||
await documents.create_document(document=document)
|
||||
|
||||
source = Source(
|
||||
document_id=document.id,
|
||||
page_number=1,
|
||||
upload_name="orphan.jpg",
|
||||
filename="orphan.jpg",
|
||||
file_path="uploads/orphan.jpg",
|
||||
)
|
||||
await transcriptions.create_source(source=source)
|
||||
|
||||
await transcriptions.delete_unlinked_source(source_id=source.id)
|
||||
|
||||
with pytest.raises(TranscriptionNotFoundError):
|
||||
await transcriptions.read_source(source.id)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_delete_unlinked_source_blocks_when_linked(self, default_session_factory):
|
||||
documents = DocumentService(session_factory=default_session_factory)
|
||||
jobs = JobService(session_factory=default_session_factory)
|
||||
transcriptions = TranscriptionService(session_factory=default_session_factory)
|
||||
|
||||
document = Document(id=uuid4(), name="delete-unlinked-blocked")
|
||||
await documents.create_document(document=document)
|
||||
|
||||
job = Job(document_id=document.id, status=JobStatus.QUEUED)
|
||||
await jobs.create_job(job=job)
|
||||
|
||||
source = Source(
|
||||
document_id=document.id,
|
||||
page_number=1,
|
||||
upload_name="linked.jpg",
|
||||
filename="linked.jpg",
|
||||
file_path="uploads/linked.jpg",
|
||||
)
|
||||
async with transcriptions._session_scope() as session:
|
||||
session.add(source)
|
||||
await session.flush()
|
||||
session.add(JobSource(job_id=job.id, source_id=source.id, status=JobSourceStatus.PENDING))
|
||||
await session.commit()
|
||||
await session.refresh(source)
|
||||
|
||||
with pytest.raises(SourceDeleteBlockedError):
|
||||
await transcriptions.delete_unlinked_source(source_id=source.id)
|
||||
|
||||
Reference in New Issue
Block a user