case 4755 - automatic backup no longer skips a day after a restart or a manual backup
SetNextBackup counted "tomorrow" from the day the server started, using the newest backup file as the last backup, so a restart between midnight and the backup time (every Thursday reboot), a manual backup, or a backup finishing after midnight skipped a day. The next backup is now simply the next time the backup time comes round on the server's clock. A time that happens twice when the clocks go back runs at the first one only. Tested with a minute-by-minute simulation over both daylight saving changes (one backup every day; the old code skipped days) and on the local server. Changelog line; two Deferred entries (dead inputs, safe headers missing on handler 500s). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -282,6 +282,8 @@ Found during the port, out of scope. One line each.
|
||||
- From case 4697 (John: Deferred): (1) a relative date range that crosses a daylight saving change can be an hour off at its far end, because the client sends only its current offset with list requests; exact would need the client to send its IANA time zone name too (front-end change). (2) Dashboard widgets group by day, week or month with `date_trunc` on the stored UTC times, so for a user far from UTC an item near midnight lands in the neighbouring bar; same need for the time zone name
|
||||
- From case 4727 (John: later hardening case, 2026-10-26): AyaNova runs as `www-data` on droplets and in the Linux manual (as in Microsoft's ASP.NET Core with NGINX guide), the same account as NGINX's workers, so NGINX can read `config.json` (database password) and write `data`. A dedicated `ayanova` system account isolates them: service `User=`, ownership, the setup script and the manual, plus a migration for existing droplets and self-hosted installs
|
||||
- Found in the case 4727 droplet test (2026-10-26; John: later case, early in a future release so every other test exercises it): stopping the service sometimes logs `ObjectDisposedException` from `JobsBiz.ProcessJobsAsync`, and the server-problem notification it tries to raise fails the same way, so nothing is sent. Pre-existing: 8.2.4 on devtest logged it at 2 of its last 40 stops (2026-09-10, 2026-10-01). Cause: `GeneratorService.StopAsync` (`generator/Generate.cs`) is overridden to return at once without calling `base.StopAsync`, so the host neither signals the job loop nor waits for it, and disposes its services while a pass may still be running; `Task.Delay(1000)` also ignores the stopping token. Fix: remove the override (or call the base) and pass the token to `Task.Delay`; test stopping during a report render and a backup, since shutdown would then wait for the running pass
|
||||
- From case 4755 (tidy-up, no behaviour change): `SetNextBackup` no longer reads `NextBackup`'s previous value, so the startup line `NextBackup = FileUtil.MostRecentAutomatedBackupFileDate()` (`util/ServerGlobalOpsSettingsCache.cs:50`), the reset to `DateTime.MinValue` in `GlobalOpsBackupSettingsBiz` and `FileUtil.MostRecentAutomatedBackupFileDate` itself are dead. Same in Sockeye
|
||||
- Found in case 4755's integration run (2026-10-31): a 500 response produced by the exception handler (e.g. `/` on a debug server whose `wwwroot` has no client) has none of the three safe headers from case 4727 (F35), because the handler clears headers set before it. Integration test `ApiRoute.SafeHeadersOnEveryResponse` fails for that reason on a debug server without the client in `wwwroot`; it passes on a release build
|
||||
- Pre-existing (found in the 4632 IIS test, John: Deferred): emailed report attachments have the content type `application/pdf/pdf`, because `Mailer.cs:51` builds `new MimePart("application/pdf", "pdf")` (media type and subtype) instead of `new MimePart("application", "pdf")`. Mail programs still open the file by its `.pdf` name
|
||||
|
||||
## Log
|
||||
|
||||
@@ -12,6 +12,10 @@ See the [upgrade instructions](ops-upgrade.md) section of this manual for detail
|
||||
|
||||
IN PROGRESS
|
||||
|
||||
**Changed**
|
||||
|
||||
- Server: in some cases the automatic backup could be skipped for one day after the AyaNova server was restarted or a manual backup was made; it now always runs at the next chosen [backup time](ops-form-backup.md#backup-time).
|
||||
|
||||
### AyaNova 8.3.0
|
||||
|
||||
**WARNING:** this release contains changes that will require a **pre upgrade step** on all Windows and Linux network platforms from the normal upgrade process you may be accustomed to. Be sure to follow our [upgrade instructions](ops-upgrade.md) and the **pre upgrade step** for your platform for this particular upgrade from version 8.2.4 (or older) to version 8.3.0 (or newer).
|
||||
|
||||
@@ -65,20 +65,12 @@ namespace AyaNova.Util
|
||||
DateTime utcNow = DateTime.UtcNow;
|
||||
//case 4682: the backup time is a time on the server's clock; days are the server's local days
|
||||
DateTime localToday = TimeZoneInfo.ConvertTimeFromUtc(utcNow, TimeZoneInfo.Local).Date;
|
||||
//Has last backup run more than 24 hours ago?
|
||||
if (NextBackup < utcNow.AddHours(-24))
|
||||
{
|
||||
//set it to today then
|
||||
NextBackup = BackupTimeOnLocalDay(localToday);
|
||||
//Make sure next backup is in the future
|
||||
if (NextBackup < utcNow)
|
||||
NextBackup = BackupTimeOnLocalDay(localToday.AddDays(1));
|
||||
}
|
||||
else
|
||||
{
|
||||
//less than 24 hours, set it to tomorrow
|
||||
//case 4755: the next backup is the next time the backup time comes round on the server's clock: today's if it is
|
||||
//still ahead, otherwise tomorrow's. It no longer counts from the last backup, which skipped a night after a restart
|
||||
//between midnight and the backup time, or after a manual backup
|
||||
NextBackup = BackupTimeOnLocalDay(localToday);
|
||||
if (NextBackup <= utcNow)
|
||||
NextBackup = BackupTimeOnLocalDay(localToday.AddDays(1));
|
||||
}
|
||||
}
|
||||
|
||||
//case 4682: the backup time is stored as the UTC moment it meant on the day it was set, and was run at that UTC hour
|
||||
@@ -91,6 +83,9 @@ namespace AyaNova.Util
|
||||
//a time skipped when the clocks go forward (e.g. 2:30 AM that night) runs an hour later
|
||||
if (TimeZoneInfo.Local.IsInvalidTime(local))
|
||||
local = local.AddHours(1);
|
||||
//case 4755: a time that happens twice when the clocks go back (e.g. 1:30 AM that night) runs at the first one only
|
||||
if (TimeZoneInfo.Local.IsAmbiguousTime(local))
|
||||
return new DateTimeOffset(local, TimeZoneInfo.Local.GetAmbiguousTimeOffsets(local).Max()).UtcDateTime;
|
||||
return TimeZoneInfo.ConvertTimeToUtc(local, TimeZoneInfo.Local);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user