Fail deliveries on archive errors; validate expiry at creation (#43)
Some checks failed
check / check (push) Failing after 57s
Some checks failed
check / check (push) Failing after 57s
Two review findings on the database archiving target: - An archive error now records the attempt as failed with the error string and marks the delivery failed, instead of logging the error and reporting success. A target that could not do its one job must not claim it did. - The archive expiry is now actually configurable: the add-target form gains an expiry field for database targets, and the value is validated at creation time via the new delivery.ValidateArchiveExpiry (empty, "never", or a positive Go duration), rejecting bad values with a 400 at the only place a human can fix them, mirroring how Slack target URLs are validated at creation. Test updates: a forced archive failure asserts a failed delivery with a recorded error and no archive file; config builder tests cover empty/never/duration and rejection paths; the two engine tests that exercise the database target now build engines with a real webhook DB manager since archiving is no longer a no-op; the reopen-debounce test uses a wider window so parallel test load cannot make two rapid writes straddle it.
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/google/uuid"
|
||||
@@ -903,7 +904,9 @@ func (h *Handlers) buildTargetConfig(
|
||||
return h.buildHTTPTargetConfig(w, r, targetURL)
|
||||
case database.TargetTypeSlack:
|
||||
return h.buildSlackTargetConfig(w, r, targetURL)
|
||||
case database.TargetTypeDatabase, database.TargetTypeLog:
|
||||
case database.TargetTypeDatabase:
|
||||
return h.buildDatabaseTargetConfig(w, r)
|
||||
case database.TargetTypeLog:
|
||||
return "", nil
|
||||
default:
|
||||
http.Error(
|
||||
@@ -1013,6 +1016,47 @@ func (h *Handlers) buildSlackTargetConfig(
|
||||
return string(configBytes), nil
|
||||
}
|
||||
|
||||
// buildDatabaseTargetConfig builds config JSON for a database
|
||||
// (archive) target. The optional expiry form value is validated
|
||||
// here, at creation time, so an unparseable value is rejected
|
||||
// with a 400 instead of failing every subsequent delivery. An
|
||||
// empty expiry yields an empty config (the keep-forever
|
||||
// default).
|
||||
func (h *Handlers) buildDatabaseTargetConfig(
|
||||
w http.ResponseWriter,
|
||||
r *http.Request,
|
||||
) (string, error) {
|
||||
expiry := strings.TrimSpace(r.FormValue("expiry"))
|
||||
if expiry == "" {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
err := delivery.ValidateArchiveExpiry(expiry)
|
||||
if err != nil {
|
||||
http.Error(
|
||||
w,
|
||||
"Invalid archive expiry: "+err.Error(),
|
||||
http.StatusBadRequest,
|
||||
)
|
||||
|
||||
return "", err
|
||||
}
|
||||
|
||||
cfg := map[string]any{"expiry": expiry}
|
||||
|
||||
configBytes, err := json.Marshal(cfg)
|
||||
if err != nil {
|
||||
http.Error(
|
||||
w, "Internal server error",
|
||||
http.StatusInternalServerError,
|
||||
)
|
||||
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(configBytes), nil
|
||||
}
|
||||
|
||||
// HandleEntrypointDelete handles deleting an entrypoint.
|
||||
func (h *Handlers) HandleEntrypointDelete() http.HandlerFunc {
|
||||
return h.deleteChildResource(
|
||||
|
||||
Reference in New Issue
Block a user