Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Parallelise uploads #16268

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
k0raph wants to merge 131 commits into nextcloud:master
base: master
Choose a base branch
Loading
from k0raph:parallelise-uploads
Open

Parallelise uploads #16268

k0raph wants to merge 131 commits into nextcloud:master from k0raph:parallelise-uploads

Conversation

@k0raph
Copy link

@k0raph k0raph commented Jan 12, 2026
edited
Loading

Issue: #10124

This PR aims to introduce improvements to the file upload process by parallelizing uploads using Kotlin Coroutines and a Semaphore (which I defaulted to 5 concurrent tasks) to improve throughput.

Key Changes

  1. Changing BackgroundJobManagerImpl.startFilesUploadJob() to launch multiple FileUploadWorkers
  2. Compatibility change in FileUploadHelper.kt
  3. Unit tests for FileUploadWorker.kt (extracted out dependencies to make testing easier)
  4. Unit tests for BackgroundJobManagerImpl.startFilesUploadJob()
  5. Unit test for FileUploadHelper
parallel-uploads-notification-bar parallel-uploads-uploads-list
  • Tests written, or not not needed

Peacemanguy and BluePixel4k reacted with thumbs up emoji BluePixel4k, rmelotte, and MightyHelper reacted with heart emoji
Copy link
Collaborator

@alperozturk96 alperozturk96 left a comment

Choose a reason for hiding this comment

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

Hello

Thank you for the PR 👍

I really appreciate the time and effort you’ve put into this.

I wanted to share some feedback after reviewing the changes. Using ConcurrentHashMap, Semaphore, atomics, and synchronized blocks to achieve parallel uploads makes the implementation quite fragile and hard to maintain in the long run. It also increases complexity in an area of the codebase that is already fairly sensitive.

In fact, we can achieve parallel uploads with a much simpler change. Currently, in BackgroundJobManagerImpl, the startFilesUploadJob function uses the same worker tag together with the ExistingWorkPolicy.APPEND_OR_REPLACE policy. Because of this, a new worker is not used for each upload attempt; instead, uploads are queued and executed sequentially.

By making the tag unique (for example, by appending a random value), a new worker will be started for each upload, enabling parallelism with minimal changes:

val tag = startFileUploadJobTag(user.accountName + Random.nextInt())


Introducing parallel uploads is definitely a good idea, but it’s something we should approach incrementally and carefully to ensure the overall robustness of the app. FileUploadWorker is a critical component: it also triggers UI updates via the broadcast manager and is observed by multiple screens. Making it parallel will likely have side effects in those areas (notifications, upload list, file listing, etc.), so we need to be mindful of that impact.

I’d suggest the following approach:

  1. Enable parallel uploads with the minimal change (unique worker tags).

  2. Observe and adjust the behavior of the caller functions, and add appropriate tests.

  3. Observe UI behavior (notifications, file list, upload list) and address any issues that arise.

Thanks again for your contribution and initiative on this topic. :)

@ZetaTom @tobiasKaminsky fyi.

ZetaTom reacted with thumbs up emoji k0raph reacted with eyes emoji
Copy link
Author

k0raph commented Jan 20, 2026

Hello

Thank you for the PR 👍

I really appreciate the time and effort you’ve put into this.

I wanted to share some feedback after reviewing the changes. Using ConcurrentHashMap, Semaphore, atomics, and synchronized blocks to achieve parallel uploads makes the implementation quite fragile and hard to maintain in the long run. It also increases complexity in an area of the codebase that is already fairly sensitive.

In fact, we can achieve parallel uploads with a much simpler change. Currently, in BackgroundJobManagerImpl, the startFilesUploadJob function uses the same worker tag together with the ExistingWorkPolicy.APPEND_OR_REPLACE policy. Because of this, a new worker is not used for each upload attempt; instead, uploads are queued and executed sequentially.

By making the tag unique (for example, by appending a random value), a new worker will be started for each upload, enabling parallelism with minimal changes:

val tag = startFileUploadJobTag(user.accountName + Random.nextInt())

Introducing parallel uploads is definitely a good idea, but it’s something we should approach incrementally and carefully to ensure the overall robustness of the app. FileUploadWorker is a critical component: it also triggers UI updates via the broadcast manager and is observed by multiple screens. Making it parallel will likely have side effects in those areas (notifications, upload list, file listing, etc.), so we need to be mindful of that impact.

I’d suggest the following approach:

1. Enable parallel uploads with the minimal change (unique worker tags).
2. Observe and adjust the behavior of the caller functions, and add appropriate tests.
3. Observe UI behavior (notifications, file list, upload list) and address any issues that arise.

Thanks again for your contribution and initiative on this topic. :)

@ZetaTom @tobiasKaminsky fyi.

Thank you @alperozturk96 for taking the time to review and I appreciate you sharing your expertise in this area. I don't disagree with any of the comments and I will happily explore your suggestion.

Copy link
Author

k0raph commented Jan 20, 2026
edited
Loading

@alperozturk96 I have looked into your suggestion, and managed to get it working. It's significantly less changes and anecdotally seems to run much faster =]. Unfortunately it has had the side effects you mentioned. Notably the upload list is not reflective of the parallel nature (multiple files should be marked as uploading) - I am not sure how to address this without the ConcurrentHashMap solution I previously incorporated into FileUploadWorker. Could you please advise in this case?
broken-uploads-list-only-marks-1-uploading-at-a-time
Additionally the notifications are now also broken, the numerators are all over the place - I don't have a solution for this yet. Will investigate
broken-notifications

May I also clarify what you mean by "file list"?

BluePixel4k reacted with thumbs up emoji

Copy link
Member

kra-mo commented Jan 22, 2026
edited
Loading

From a design POV, "max concurrent uploads" should definitely not be a user-configurable setting. Just pick a sensible default and stick with that. If it doesn't work for everyone, we should investigate then.

jancborchardt reacted with thumbs up emoji

Copy link
Author

k0raph commented Jan 22, 2026

From a design POV, "max concurrent uploads" should definitely not be a user-configurable setting. Just pick a sensible default and stick with that. If it doesn't work for everyone, we should investigate then.

Hey @kra-mo happy to remove the configurability and simply default, but could you help me understand why it "should definitely not be user configurable?". Seems like a useful reasonable option at a glance

Alternatively if the fear is that we are giving the user "a foot gun", we can provide a limited selection of options 1,2,5,10,20?

Copy link
Member

kra-mo commented Jan 22, 2026

It's against our design principles:

Software should get out of the way. Do things automatically instead of offering configuration options. When people ask for a setting, find out what the root of the problem is and fix that instead. Also read Choosing our Preferences.

From https://docs.nextcloud.com/server/27/developer_manual/design/introduction.html

But TL;DR the more preferences you have that most users shouldn't touch, the harder it is to find ones that they do care about. If there is no reason for something to be configurable other than "why not", it's best to just not :)

jancborchardt reacted with thumbs up emoji

Copy link
Member

kra-mo commented Jan 22, 2026

If there is a need to have different numbers of for different scenarios, it'll probably come up, and we can probably solve it for that scenario automatically, as the developers. We shouldn't put the burden on the user.

Copy link
Author

k0raph commented Jan 22, 2026

@kra-mo great response, consider me convinced. I will revert the changes and default

BluePixel4k reacted with thumbs up emoji kra-mo reacted with heart emoji

tobiasKaminsky and others added 12 commits January 24, 2026 01:20
Signed-off-by: tobiasKaminsky <tobias@kaminsky.me>
Signed-off-by: Raphael Vieira <raphaelecv@hotmail.com>
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Signed-off-by: Raphael Vieira <raphaelecv@hotmail.com>
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Signed-off-by: Raphael Vieira <raphaelecv@hotmail.com>
Signed-off-by: tobiasKaminsky <tobias@kaminsky.me>
Signed-off-by: Raphael Vieira <raphaelecv@hotmail.com>
Signed-off-by: alperozturk <alper_ozturk@proton.me>
Signed-off-by: Raphael Vieira <raphaelecv@hotmail.com>
The ICS event file has been updated to follow proper RFC 5545 formatting.
Changes:
- Added a valid DESCRIPTION field instead of an empty one
- Unified DTSTART and DTEND to use the same TZID (Europe/Berlin)
- Ensured the event duration is correct and consistent
- Cleaned up extra blank lines to avoid parsing issues
- Retained the complete VTIMEZONE block for compatibility with Nextcloud, Google Calendar, and iOS
This improves interoperability with calendar clients and prevents parsing errors caused by mixed time formats.
Signed-off-by: Gorlesunilkumar <g2005.sunil2005@gmail.com>
Signed-off-by: Raphael Vieira <raphaelecv@hotmail.com>
Signed-off-by: nextcloud-android-bot <android@nextcloud.com>
Signed-off-by: Raphael Vieira <raphaelecv@hotmail.com>
Signed-off-by: tobiasKaminsky <tobias@kaminsky.me>
Signed-off-by: Raphael Vieira <raphaelecv@hotmail.com>
...ad safe vars and make sure UI updates accordingly
Signed-off-by: Raphael Vieira <raphaelecv@hotmail.com>
... safety
Signed-off-by: Raphael Vieira <raphaelecv@hotmail.com>
...progress
Signed-off-by: Raphael Vieira <raphaelecv@hotmail.com>
Signed-off-by: Raphael Vieira <raphaelecv@hotmail.com>
AndyScherzinger and others added 18 commits January 24, 2026 01:25
Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
Signed-off-by: Raphael Vieira <raphaelecv@hotmail.com>
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
Signed-off-by: Raphael Vieira <raphaelecv@hotmail.com>
Signed-off-by: alperozturk <alper_ozturk@proton.me>
Signed-off-by: Raphael Vieira <raphaelecv@hotmail.com>
Signed-off-by: alperozturk <alper_ozturk@proton.me>
Signed-off-by: Raphael Vieira <raphaelecv@hotmail.com>
Signed-off-by: nextcloud-android-bot <android@nextcloud.com>
Signed-off-by: Raphael Vieira <raphaelecv@hotmail.com>
Signed-off-by: alperozturk96 <alper_ozturk@proton.me>
Signed-off-by: Raphael Vieira <raphaelecv@hotmail.com>
Co-authored-by: Tom <70907959+ZetaTom@users.noreply.github.com>
Signed-off-by: Alper Öztürk <67455295+alperozturk96@users.noreply.github.com>
Signed-off-by: Raphael Vieira <raphaelecv@hotmail.com>
Co-authored-by: Tom <70907959+ZetaTom@users.noreply.github.com>
Signed-off-by: Alper Öztürk <67455295+alperozturk96@users.noreply.github.com>
Signed-off-by: Raphael Vieira <raphaelecv@hotmail.com>
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
Signed-off-by: Raphael Vieira <raphaelecv@hotmail.com>
Signed-off-by: alperozturk96 <alper_ozturk@proton.me>
Signed-off-by: Raphael Vieira <raphaelecv@hotmail.com>
Signed-off-by: alperozturk96 <alper_ozturk@proton.me>
Signed-off-by: Raphael Vieira <raphaelecv@hotmail.com>
Signed-off-by: alperozturk96 <alper_ozturk@proton.me>
Signed-off-by: Raphael Vieira <raphaelecv@hotmail.com>
Signed-off-by: alperozturk96 <alper_ozturk@proton.me>
Signed-off-by: Raphael Vieira <raphaelecv@hotmail.com>
Signed-off-by: alperozturk96 <alper_ozturk@proton.me>
Signed-off-by: Raphael Vieira <raphaelecv@hotmail.com>
Signed-off-by: alperozturk96 <alper_ozturk@proton.me>
Signed-off-by: Raphael Vieira <raphaelecv@hotmail.com>
Signed-off-by: alperozturk96 <alper_ozturk@proton.me>
Signed-off-by: Raphael Vieira <raphaelecv@hotmail.com>
Signed-off-by: alperozturk96 <alper_ozturk@proton.me>
Signed-off-by: Raphael Vieira <raphaelecv@hotmail.com>
Signed-off-by: Raphael Vieira <raphaelecv@hotmail.com>
k0raph added 3 commits January 24, 2026 01:30
Signed-off-by: Raphael Vieira <raphaelecv@hotmail.com>
Signed-off-by: Raphael Vieira <raphaelecv@hotmail.com>
Copy link

Hello there,
Thank you so much for taking the time and effort to create a pull request to our Nextcloud project.

We hope that the review process is going smooth and is helpful for you. We want to ensure your pull request is reviewed to your satisfaction. If you have a moment, our community management team would very much appreciate your feedback on your experience with this PR review process.

Your feedback is valuable to us as we continuously strive to improve our community developer experience. Please take a moment to complete our short survey by clicking on the following link: https://cloud.nextcloud.com/apps/forms/s/i9Ago4EQRZ7TWxjfmeEpPkf6

Thank you for contributing to Nextcloud and we hope to hear from you soon!

(If you believe you should not receive this message, you can add yourself to the blocklist.)

Copy link
Author

k0raph commented Jan 30, 2026

@alperozturk96 @kra-mo @tobiasKaminsky could I get a re-review

Signed-off-by: Raphael Vieira <raphaelecv@hotmail.com>
Copy link
Member

Hello,

thank you for this valuable PR.
Since this is a quite big (and "severe") change, I am a bit of hesitating to merge this soon.
Imagine if in some corner cases (like slow network) none of the parallel uploads finish.

Thus I think we need to have a way to test/make sure that it is robust in many cases.

We have our dev app, which we could use for that.
So I suggest to check if it is possible to bound this to "is_beta" in setup.xml?

This way we can enable it for dev versions, monitor the replies and then at some point enable it.
Before we merge it, we should also do intensive tests on our own.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@tobiasKaminsky tobiasKaminsky Awaiting requested review from tobiasKaminsky

@jancborchardt jancborchardt Awaiting requested review from jancborchardt

@kra-mo kra-mo Awaiting requested review from kra-mo

@alperozturk96 alperozturk96 Awaiting requested review from alperozturk96

1 more reviewer

@Peacemanguy Peacemanguy Peacemanguy left review comments

Reviewers whose approvals may not affect merge requirements

Requested changes must be addressed to merge this pull request.

Assignees

No one assigned

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

AltStyle によって変換されたページ (->オリジナル) /