diff --git a/cmd/cmd.go b/cmd/cmd.go index 73fe98a2d..01102473e 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -35,6 +35,7 @@ import ( fslog "github.com/rclone/rclone/fs/log" "github.com/rclone/rclone/fs/rc/rcflags" "github.com/rclone/rclone/fs/rc/rcserver" + fssync "github.com/rclone/rclone/fs/sync" "github.com/rclone/rclone/lib/atexit" "github.com/rclone/rclone/lib/buildinfo" "github.com/rclone/rclone/lib/exitcode" @@ -501,6 +502,8 @@ func resolveExitCode(err error) { os.Exit(exitcode.UncategorizedError) case errors.Is(err, accounting.ErrorMaxTransferLimitReached): os.Exit(exitcode.TransferExceeded) + case errors.Is(err, fssync.ErrorMaxDurationReached): + os.Exit(exitcode.DurationExceeded) case fserrors.ShouldRetry(err): os.Exit(exitcode.RetryError) case fserrors.IsNoRetryError(err), fserrors.IsNoLowLevelRetryError(err): diff --git a/docs/content/docs.md b/docs/content/docs.md index 5800699f7..f69e4d4bb 100644 --- a/docs/content/docs.md +++ b/docs/content/docs.md @@ -1454,14 +1454,14 @@ what will happen. ### --max-duration=TIME ### -Rclone will stop scheduling new transfers when it has run for the +Rclone will stop transferring when it has run for the duration specified. - Defaults to off. -When the limit is reached any existing transfers will complete. +When the limit is reached all transfers will stop immediately. +Use `--cutoff-mode` to modify this behaviour. -Rclone won't exit with an error if the transfer limit is reached. +Rclone will exit with exit code 10 if the duration limit is reached. ### --max-transfer=SIZE ### @@ -1469,9 +1469,24 @@ Rclone will stop transferring when it has reached the size specified. Defaults to off. When the limit is reached all transfers will stop immediately. +Use `--cutoff-mode` to modify this behaviour. Rclone will exit with exit code 8 if the transfer limit is reached. +### --cutoff-mode=hard|soft|cautious ### + +This modifies the behavior of `--max-transfer` and `--max-duration` +Defaults to `--cutoff-mode=hard`. + +Specifying `--cutoff-mode=hard` will stop transferring immediately +when Rclone reaches the limit. + +Specifying `--cutoff-mode=soft` will stop starting new transfers +when Rclone reaches the limit. + +Specifying `--cutoff-mode=cautious` will try to prevent Rclone +from reaching the limit. Only applicable for `--max-transfer` + ## -M, --metadata Setting this flag enables rclone to copy the metadata from the source @@ -1484,20 +1499,6 @@ Add metadata `key` = `value` when uploading. This can be repeated as many times as required. See the [#metadata](metadata section) for more info. -### --cutoff-mode=hard|soft|cautious ### - -This modifies the behavior of `--max-transfer` -Defaults to `--cutoff-mode=hard`. - -Specifying `--cutoff-mode=hard` will stop transferring immediately -when Rclone reaches the limit. - -Specifying `--cutoff-mode=soft` will stop starting new transfers -when Rclone reaches the limit. - -Specifying `--cutoff-mode=cautious` will try to prevent Rclone -from reaching the limit. - ### --modify-window=TIME ### When checking whether a file has been modified, this is the maximum @@ -2561,6 +2562,7 @@ it will log a high priority message if the retry was successful. * `7` - Fatal error (one that more retries won't fix, like account suspended) (Fatal errors) * `8` - Transfer exceeded - limit set by --max-transfer reached * `9` - Operation successful, but no files transferred + * `10` - Duration exceeded - limit set by --max-duration reached Environment Variables --------------------- diff --git a/docs/content/flags.md b/docs/content/flags.md index 8fbe43a4a..8e816d34a 100644 --- a/docs/content/flags.md +++ b/docs/content/flags.md @@ -86,7 +86,7 @@ These flags are available for every command. --max-delete int When synchronizing, limit the number of deletes (default -1) --max-delete-size SizeSuffix When synchronizing, limit the total size of deletes (default off) --max-depth int If set limits the recursion depth to this (default -1) - --max-duration Duration Maximum duration rclone will transfer data for (default 0s) + --max-duration Duration Maximum duration rclone will transfer data for (default off) --max-size SizeSuffix Only transfer files smaller than this in KiB or suffix B|K|M|G|T|P (default off) --max-stats-groups int Maximum number of stats groups to keep in memory, on max oldest is discarded (default 1000) --max-transfer SizeSuffix Maximum size of data to transfer (default off) diff --git a/fs/sync/sync.go b/fs/sync/sync.go index f3da4adf3..96f7e30de 100644 --- a/fs/sync/sync.go +++ b/fs/sync/sync.go @@ -20,6 +20,14 @@ import ( "github.com/rclone/rclone/fs/operations" ) +// ErrorMaxDurationReached defines error when transfer duration is reached +// Used for checking on exit and matching to correct exit code. +var ErrorMaxDurationReached = errors.New("max transfer duration reached as set by --max-duration") + +// ErrorMaxDurationReachedFatal is returned from when the max +// duration limit is reached. +var ErrorMaxDurationReachedFatal = fserrors.FatalError(ErrorMaxDurationReached) + type syncCopyMove struct { // parameters fdst fs.Fs @@ -845,10 +853,6 @@ func (s *syncCopyMove) tryRename(src fs.Object) bool { return true } -// errorMaxDurationReached defines error when transfer duration is reached -// Used for checking on exit and matching to correct exit code. -var errorMaxDurationReached = fserrors.FatalError(errors.New("max transfer duration reached as set by --max-duration")) - // Syncs fsrc into fdst // // If Delete is true then it deletes any files in fdst that aren't in fsrc @@ -945,8 +949,8 @@ func (s *syncCopyMove) run() error { // If the duration was exceeded then add a Fatal Error so we don't retry if !s.maxDurationEndTime.IsZero() && time.Since(s.maxDurationEndTime) > 0 { - fs.Errorf(s.fdst, "%v", errorMaxDurationReached) - s.processError(errorMaxDurationReached) + fs.Errorf(s.fdst, "%v", ErrorMaxDurationReachedFatal) + s.processError(ErrorMaxDurationReachedFatal) } // Print nothing to transfer message if there were no transfers and no errors diff --git a/fs/sync/sync_test.go b/fs/sync/sync_test.go index fd05e9f44..99b425ebe 100644 --- a/fs/sync/sync_test.go +++ b/fs/sync/sync_test.go @@ -996,7 +996,7 @@ func testSyncWithMaxDuration(t *testing.T, cutoffMode fs.CutoffMode) { accounting.GlobalStats().ResetCounters() startTime := time.Now() err := Sync(ctx, r.Fremote, r.Flocal, false) - require.True(t, errors.Is(err, errorMaxDurationReached)) + require.True(t, errors.Is(err, ErrorMaxDurationReached)) if cutoffMode == fs.CutoffModeHard { r.CheckRemoteItems(t, file1) diff --git a/lib/exitcode/exitcode.go b/lib/exitcode/exitcode.go index 7b850cdb8..6cedb3303 100644 --- a/lib/exitcode/exitcode.go +++ b/lib/exitcode/exitcode.go @@ -22,4 +22,6 @@ const ( TransferExceeded // NoFilesTransferred everything succeeded, but no transfer was made. NoFilesTransferred + // DurationExceeded is returned when transfer duration exceeded the quota. + DurationExceeded )