A backup is a directory <stamp>-<kind> under Backups:Root (/var/lib/privapub/backups, 2770, files 0640), written as .partial and renamed once whole: a manifest (host, build, newest migration, each collection's count, size, sha256 and indexes, what was left out and why, the media list), each collection as gzipped canonical Extended JSON read raw, and hard links to the files of untrashed media rows (copies where a link can't be made). On a replica set every collection is read in one snapshot session. Never in a backup: the statistics salt, jobs, recovery codes, sessions, the maintenance lock and the configuration's copy with its SMTP password. One backup or restore at a time (MaintenanceLock, a heartbeat document), and the janitor purges nothing meanwhile. BackupScheduler backs up nightly at 03:30 UTC (or at once after missing a night); rotation keeps 7 daily, 4 weekly, 3 pre-deploy and 3 pre-restore backups. CLI: admin backup [--kind] [--db-only], admin backups, admin backup verify; these run before migrations, so the deploy's own pre-deploy backup, which replaces mongodump, is of the database as the live build left it. EntityMaps.Warm runs once under a lock, since test hosts now boot side by side. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw
34 lines
887 B
C#
34 lines
887 B
C#
using MongoDB.Entities;
|
|
|
|
namespace PrivaPub.Infrastructure.Data
|
|
{
|
|
public static class EntityMaps
|
|
{
|
|
static readonly Lock Gate = new();
|
|
static bool _warm;
|
|
|
|
// once per process, one map at a time: test hosts boot side by side
|
|
public static void Warm()
|
|
{
|
|
lock (Gate)
|
|
{
|
|
if (_warm)
|
|
return;
|
|
Map();
|
|
_warm = true;
|
|
}
|
|
}
|
|
|
|
static void Map()
|
|
{
|
|
var collection = typeof(DB).GetMethods()
|
|
.Single(m => m.Name == nameof(DB.Collection) && m.IsGenericMethodDefinition && m.GetParameters().Length == 0);
|
|
var entities = typeof(EntityMaps).Assembly.GetTypes()
|
|
.Where(t => t is { IsClass: true, IsAbstract: false, IsGenericTypeDefinition: false } && typeof(IEntity).IsAssignableFrom(t))
|
|
.OrderBy(t => t.FullName, StringComparer.Ordinal);
|
|
foreach (var entity in entities)
|
|
collection.MakeGenericMethod(entity).Invoke(DB.Default, null);
|
|
}
|
|
}
|
|
}
|