Problem
When every transfer has succeeded but the final status flip fails, upload_files raises and the caller loses the UploadSummary — so it never learns which files actually landed, or the workunit id.
operations/workunit/upload.py:277:
elif created:
# Intentionally outside the try/except above: the bytes have already landed, so a failure of
# this final status flip should surface as-is rather than mark a workunit-with-real-content
# 'failed'. It stays 'processing' and the exception propagates for the caller to retry.
_ = complete_workunit(client=client, workunit_id=workunit_id)
Not marking the workunit failed is right, and the comment explains why. The problem is only that the raise is bare: the summary describing a successful upload is discarded along with it.
Observed consequence
Hit while testing BioBeamer's tus backend. A run uploaded both groups' bytes successfully; the second group's complete_workunit then failed:
14:23:58 group 1 -> workunit 346730, 2 uploaded
14:24:04 group 2 -> Query was not successful: Invalid or expired token.
(The token error was our own fault — the local B-Fabric's OAuth issuer had been switched from fgcz-test to localhost mid-session, so the JWT was valid but for the wrong issuer. Not a bfabricpy bug. The summary loss is the point here.)
Because the exception carried nothing, the retry had no way to know those files were already stored. It created a second workunit (346732) linking to the first one's bytes — a duplicate workunit for one acquisition. The bytes were fine either way; the bookkeeping was not.
Worth noting the storage service's post-finish hook had already set the resources and workunit to AVAILABLE, so complete_workunit may be partly redundant on the tus path — possibly worth confirming with the storage-service side whether it needs to run at all there.
Suggested fix
Attach the completed summary to the exception, e.g.:
class WorkunitCompletionError(BfabricTransferError):
"""The upload finished but the workunit's final status flip failed."""
def __init__(self, message, summary: UploadSummary): ...
Behaviour otherwise unchanged: still raises, still leaves the workunit processing, still does not mark it failed. But a caller can then record what transferred and retry only the status flip instead of re-uploading or creating a second workunit.
For reference, BioBeamer needed the same shape one level up and solved it the same way (TusUploadFailed carrying files_copied), so that partial successes still reach the copied-files ledger before the run fails.
Problem
When every transfer has succeeded but the final status flip fails,
upload_filesraises and the caller loses theUploadSummary— so it never learns which files actually landed, or the workunit id.operations/workunit/upload.py:277:Not marking the workunit
failedis right, and the comment explains why. The problem is only that the raise is bare: the summary describing a successful upload is discarded along with it.Observed consequence
Hit while testing BioBeamer's tus backend. A run uploaded both groups' bytes successfully; the second group's
complete_workunitthen failed:(The token error was our own fault — the local B-Fabric's OAuth issuer had been switched from fgcz-test to localhost mid-session, so the JWT was valid but for the wrong issuer. Not a bfabricpy bug. The summary loss is the point here.)
Because the exception carried nothing, the retry had no way to know those files were already stored. It created a second workunit (
346732) linking to the first one's bytes — a duplicate workunit for one acquisition. The bytes were fine either way; the bookkeeping was not.Worth noting the storage service's
post-finishhook had already set the resources and workunit toAVAILABLE, socomplete_workunitmay be partly redundant on the tus path — possibly worth confirming with the storage-service side whether it needs to run at all there.Suggested fix
Attach the completed summary to the exception, e.g.:
Behaviour otherwise unchanged: still raises, still leaves the workunit
processing, still does not mark it failed. But a caller can then record what transferred and retry only the status flip instead of re-uploading or creating a second workunit.For reference, BioBeamer needed the same shape one level up and solved it the same way (
TusUploadFailedcarryingfiles_copied), so that partial successes still reach the copied-files ledger before the run fails.