Skip to content

onedrive: keep the delta token when a ChangeNotify poll fails - fixes #10009 - #10017

Open
xiaozou-wine wants to merge 1 commit into
rclone:masterfrom
xiaozou-wine:onedrive-changenotify-delta-token
Open

xiaozou-wine wants to merge 1 commit into
rclone:masterfrom
xiaozou-wine:onedrive-changenotify-delta-token

Conversation

@xiaozou-wine

Copy link
Copy Markdown

What does this change do?

Fixes three defects in the OneDrive ChangeNotify delta polling path, all in backend/onedrive/onedrive.go:

  1. A failed poll wiped the stored resume token. changeNotifyRunner returned a named nextDeltaToken which stayed "" on error, and the caller stored it unconditionally, so later polls asked for /root/delta?token= instead of resuming from the last deltaLink. Notifications then stopped until the mount was restarted. The runner now returns an explicit (string, error) and the caller only advances the stored token when err == nil.

  2. changeNotifyNextChange bypassed the pacer. It called f.srv.CallJSON directly, the only API call in the file that doesn't go through f.pacer.Call/shouldRetry, so a single transient 503 was enough to trip defect 1. It is now wrapped, so a 503 is retried honouring Retry-After.

  3. @odata.nextLink was ignored. When a change set spans more than one page Graph returns @odata.nextLink and no @odata.deltaLink, so the token parsed from the missing deltaLink came back empty and that poll's changes were dropped — with no error involved at all. The runner now walks the pages the same way _listAll already does at onedrive.go:1344.

Two httptest-based unit tests were added to onedrive_internal_test.go: one asserting that a failing poll is retried by the pacer and returns no token (so the caller retains the previous one), one asserting that every page of a multi-page change set is notified and the resume token comes from the last page. Both fail against current master.

Linked issue

Fixes #10009

For new or changed backends

This is a bug fix to an existing backend, not a new backend. I do not have a SharePoint or OneDrive account to run the integration tests against, so no test_all run is included — the verification below is unit tests only.

Verification run locally:

$ go build ./...                     # OK
$ go vet ./backend/onedrive/...      # OK
$ gofmt -l backend/onedrive/         # no output

$ go test ./backend/onedrive/ -run 'TestChangeNotify|TestTenantAPIEndpoint|TestCheckUploadCutoff' -v
--- PASS: TestTenantAPIEndpoint (0.00s)
--- PASS: TestCheckUploadCutoff (0.00s)
--- PASS: TestChangeNotifyRetriesAndKeepsToken (0.08s)
--- PASS: TestChangeNotifyFollowsNextLink (0.00s)
ok  	github.com/rclone/rclone/backend/onedrive

$ make quicktest                     # see note below

make quicktest passes for every package except cmd/nfsmount, which fails on this machine because it cannot mount FUSE (fsconfig() failed: NFS: mount program didn't pass remote address). That failure is present on unmodified master too, and is a local environment limitation rather than anything to do with this change. cmd/gitannex, which also fails if the rclone binary isn't in $PATH, passes after make.

Checklist

  • This change is trivial OR it has been discussed and agreed in the linked issue.
  • I have read the contribution guidelines.
  • (If I used AI tools to help write this code) I have read and understood the AI-assisted contributions guidance, and I have tested and take ownership of this change myself.
  • I have added tests for all changes in this PR if appropriate.
  • I have added documentation for the changes if appropriate.
  • All commit messages are in house style.
  • (Backend changes only) test_all passes for this backend and if submitting a new backend can provide a test account for the integration tester - see CONTRIBUTING.md.
  • This Pull Request is ready for review.

No documentation change: this fixes behaviour that already contradicted what the docs and the ChangeNotifier interface describe, without changing any flag or option. The test_all box is left unticked deliberately, as noted above — I'd be glad to run it if someone can point me at a test account.

…clone#10009

A failed delta poll used to wipe the stored resume token: changeNotifyRunner
returned a named nextDeltaToken which stayed empty on error, and the caller
stored it unconditionally. Later polls then asked for /root/delta?token=
instead of resuming, so notifications stopped until the mount was restarted.

changeNotifyNextChange also called the API without the pacer, so a single
transient 503 was enough to trigger this.

While fixing that, walk @odata.nextLink as well. A change set spanning more
than one page returns nextLink without a deltaLink, and the token parsed from
the missing deltaLink was empty - changes were dropped even when no error
occurred.

Fixes rclone#10009
@xiaozou-wine
xiaozou-wine force-pushed the onedrive-changenotify-delta-token branch from 8183c55 to 67e03df Compare October 2, 2026 05:01
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.

onedrive: ChangeNotify drops the delta token after one failed poll and stops notifying until remount

1 participant