Skip to content

upload_files: a failed complete_workunit discards the UploadSummary of a successful upload #614

Description

@Caushi

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions