Give a second snapshot create in the same second its own ID (closes #270)
check / check (push) Waiting to run
check / check (push) Waiting to run
The timestamp in a snapshot ID is in whole seconds, so a `snapshot create` that started in the same second as the previous run of that snapshot name got the same ID, and inserting its row failed with `UNIQUE constraint failed: snapshots.id`. CreateSnapshotWithName now looks the ID up in the local index first and, if it is taken, waits a second and takes a new timestamp. The ID format is unchanged. Only the local index is checked. That is where the insert fails, and the process lock serializes runs, so nothing takes the ID between the lookup and the insert. Model: opus-5-5
This commit was merged in pull request #277.
This commit is contained in:
@@ -115,20 +115,37 @@ func ShortHostname(hostname string) string {
|
||||
|
||||
// CreateSnapshotWithName creates a new snapshot record with an optional
|
||||
// snapshot name. The snapshot ID format is: hostname_name_timestamp or
|
||||
// hostname_timestamp if name is empty.
|
||||
// hostname_timestamp if name is empty. The timestamp is in whole seconds.
|
||||
// If the local index already has a snapshot with that ID, from a run of the
|
||||
// same name that started in the same second, it waits a second and takes a
|
||||
// new timestamp.
|
||||
func (sm *SnapshotManager) CreateSnapshotWithName(
|
||||
ctx context.Context, hostname, name, version, gitRevision string,
|
||||
) (string, error) {
|
||||
shortHostname := ShortHostname(hostname)
|
||||
|
||||
// Build snapshot ID with optional name
|
||||
timestamp := time.Now().UTC().Format("2006-01-02T15:04:05Z")
|
||||
|
||||
var snapshotID string
|
||||
if name != "" {
|
||||
snapshotID = fmt.Sprintf("%s_%s_%s", shortHostname, name, timestamp)
|
||||
} else {
|
||||
snapshotID = fmt.Sprintf("%s_%s", shortHostname, timestamp)
|
||||
|
||||
for {
|
||||
// Build snapshot ID with optional name
|
||||
timestamp := time.Now().UTC().Format("2006-01-02T15:04:05Z")
|
||||
|
||||
if name != "" {
|
||||
snapshotID = fmt.Sprintf("%s_%s_%s", shortHostname, name, timestamp)
|
||||
} else {
|
||||
snapshotID = fmt.Sprintf("%s_%s", shortHostname, timestamp)
|
||||
}
|
||||
|
||||
existing, err := sm.repos.Snapshots.GetByID(ctx, snapshotID)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("looking up snapshot %s: %w", snapshotID, err)
|
||||
}
|
||||
|
||||
if existing == nil {
|
||||
break
|
||||
}
|
||||
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
|
||||
snapshot := &database.Snapshot{
|
||||
|
||||
Reference in New Issue
Block a user