Skip to content

OUT-3584: stream Dropbox→Assembly uploads to prevent OOM crash#97

Merged
SandipBajracharya merged 2 commits intomainfrom
OUT-3584
Apr 13, 2026
Merged

OUT-3584: stream Dropbox→Assembly uploads to prevent OOM crash#97
SandipBajracharya merged 2 commits intomainfrom
OUT-3584

Conversation

@SandipBajracharya
Copy link
Copy Markdown
Collaborator

@SandipBajracharya SandipBajracharya commented Apr 13, 2026

Summary

  • Resolves OUT-3584sync-dropbox-file-to-assembly Trigger.dev task was OOMing on video files. Root cause: uploadFileInAssembly called filesDownload purely to read file size, and the Dropbox SDK buffers the entire file into a Buffer on that call. For multi-GB videos, this blew past the machine's memory limit.
  • Upload path now streams Dropbox → Assembly S3 in one pass with no full-file buffering. Machine stays on small-2x — no bump needed.
  • Content-Length for the Assembly PUT is sourced from the Dropbox download response headers, guaranteeing it matches the streamed bytes (avoids S3 Content-Length mismatch on file types where listing-time size diverges from download size).
  • Adds explicit access-token refresh in DropboxClient._downloadFile and _uploadFile. The previous code relied on an implicit refresh as a side effect of preceding SDK calls (filesDownload, filesMoveV2, etc.). Removing filesDownload exposed the regression on the download path (Dropbox 400 on unpopulated Bearer). Hardening _uploadFile with the same pattern eliminates the latent risk on the Assembly→Dropbox path.
  • Adds a ['.tag'] === 'file' guard in the resync helper so folder/deleted entries never reach the upload path after a Dropbox rename/delete-and-recreate.

Test plan

  • Trigger a Dropbox→Assembly sync on a channel with a large video file (>1 GB). Confirm the sync-dropbox-file-to-assembly task completes without OOM and the file lands in Assembly with correct bytes.
  • Trigger a full bidirectional sync on a channel with mixed file types (docs, images, videos). Confirm both directions succeed.
  • Trigger a webhook-driven delta sync (edit a file in Dropbox) and confirm the delta path uploads correctly.
  • Trigger an Assembly→Dropbox sync to confirm _uploadFile's explicit refresh doesn't regress the existing path.
  • Monitor Trigger.dev memory usage on the file-sync tasks — should stay well under small-2x's 1 GB limit.

Testing Criteria

https://www.loom.com/share/ac57be85f2784e02ac7d5ead583ae965

Screenshots

Screenshot 2026-04-13 at 15 22 02 Screenshot 2026-04-13 at 15 21 55 Screenshot 2026-04-13 at 15 21 47

🤖 Generated with Claude Code

SandipBajracharya and others added 2 commits April 13, 2026 12:49
The sync-dropbox-file-to-assembly task was OOMing on video files because
`uploadFileInAssembly` called `filesDownload` solely to read file size —
the Dropbox SDK buffers the entire file into a Buffer on that call, then
the bytes were discarded. Actual upload already streamed via a separate
path, so memory was wasted.

- Remove the buffering `filesDownload` call.
- `DropboxClient._downloadFile` now returns `{ body, contentLength }`,
  sourcing Content-Length from the download response headers so it
  always matches the streamed bytes (avoids S3 PUT mismatch on file
  types where listing-time size diverges from download size).
- Add explicit access-token refresh in `_downloadFile`. The removed
  `filesDownload` SDK call was implicitly refreshing the token; without
  it the manual fetch ran with an unpopulated Bearer and Dropbox 400'd.
- Guard resync path against non-file entries (folder/deleted) that
  could reach the upload path after a Dropbox rename/delete-and-recreate.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Mirrors the _downloadFile hardening from the previous commit. Previously
_uploadFile relied on an implicit token refresh from a preceding SDK
call (filesGetMetadata, filesMoveV2, filesCreateFolderV2) in the
Assembly→Dropbox path. That contract was fragile: any future caller
reaching _uploadFile without a prior SDK call would 400 on an
unpopulated Bearer — the same regression we just shipped in
_downloadFile.

Make the refresh explicit so the contract lives with the method, not
the call site.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@linear
Copy link
Copy Markdown

linear bot commented Apr 13, 2026

@vercel
Copy link
Copy Markdown

vercel bot commented Apr 13, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
dropbox-integration Ready Ready Preview, Comment Apr 13, 2026 7:42am

Request Review

Copy link
Copy Markdown
Collaborator

@priosshrsth priosshrsth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SandipBajracharya PR looks good. And this is a good optimization as well. Excellent job. I have added one question. But the pr has been approved.

Comment on lines +143 to +145
throw new Error(
`DropboxClient#downloadFile. Missing Content-Length header for file: ${filePath}`,
)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SandipBajracharya Do we actually expect this to be called or is it there just for type safety? And if this can be a legit cause, is it critical enough to not sync the file? Could you provide more context on what happens when we actually get this error?

Will it be marked as failed? retried again??

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When we get this error, it is retried 3 times by syncDropboxFilesToAssembly task before it completely fails. On failure we get reported via Sentry and we've also set up slack alerts. The failure of single task does not impact the overall sync. We have a trigger.dev task: resyncFailedFilesInAssembly that tries to resync those failed records.

@SandipBajracharya SandipBajracharya merged commit 4282605 into main Apr 13, 2026
4 checks passed
@SandipBajracharya SandipBajracharya changed the title fix(OUT-3584): stream Dropbox→Assembly uploads to prevent OOM crash OUT-3584: stream Dropbox→Assembly uploads to prevent OOM crash Apr 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants