refactor: improve handling of deployable fragments in ApplyRevision and buildPreviewFragments functions. Introduce isDeployableBirdFragment to filter out UI-only preview keys, and update related logic in the API to ensure proper job queuing and response handling for module refresh operations.
CI / changes (push) Successful in 5s
CI / openapi (push) Has been skipped
CI / go (push) Successful in 21s
CI / docker-web (deploy/docker/evobgp-web/Dockerfile, , evobgp-web) (push) Successful in 1m1s
CI / docker-web (deploy/docker/evobgp-web/Dockerfile, evobgp-all, evobgp-web-all) (push) Successful in 1m0s
CI / docker-bird (push) Has been skipped
CI / bird2 (push) Successful in 15s
CI / docker-go (deploy/docker/evobgp-agent/Dockerfile, , evobgp-agent) (push) Successful in 59s
CI / docker-go (evobgp-all, 1, deploy/docker/gobinary/Dockerfile, , evobgp-all) (push) Successful in 1m31s
CI / docker-go (evobgp-api, 1, deploy/docker/gobinary/Dockerfile, , evobgp-api) (push) Successful in 1m22s
CI / docker-go (evobgp-deploy, 0, deploy/docker/gobinary/Dockerfile, , evobgp-deploy) (push) Successful in 1m24s
CI / docker-go (evobgp-ingest, 0, deploy/docker/gobinary/Dockerfile, , evobgp-ingest) (push) Successful in 1m35s
CI / docker-go (evobgp-node, 0, deploy/docker/gobinary/Dockerfile, , evobgp-node) (push) Successful in 1m17s
CI / docker-go (evobgp-render, 0, deploy/docker/gobinary/Dockerfile, , evobgp-render) (push) Successful in 1m25s
CI / docker-go (evobgp-scheduler, 0, deploy/docker/gobinary/Dockerfile, , evobgp-scheduler) (push) Has been cancelled

This commit is contained in:
Denozordec
2026-04-05 23:33:56 +07:00
parent 4a860a088e
commit 693227163a
8 changed files with 288 additions and 30 deletions
+16 -4
View File
@@ -247,10 +247,6 @@ func (s *Server) handleModuleRefresh(w http.ResponseWriter, r *http.Request) {
writeProblem(w, http.StatusInternalServerError, "Internal Error", err.Error())
return
}
if mod.Type == "IP_RANGES" {
writeNoContent(w)
return
}
idem := r.Header.Get("Idempotency-Key")
var idemPtr *string
if strings.TrimSpace(idem) != "" {
@@ -320,6 +316,22 @@ func strPtrOrNull(s string) any {
return s
}
// enqueueModuleRefreshIfEnabled queues module_refresh when the module exists and is enabled (best-effort, no HTTP error).
func (s *Server) enqueueModuleRefreshIfEnabled(tenantID, moduleID, trigger string) {
if s.jobs == nil {
return
}
mod, err := s.store.GetModule(tenantID, moduleID)
if err != nil || !mod.Enabled {
return
}
mid := moduleID
_, _, _ = s.jobs.Enqueue(tenantID, jobs.KindModuleRefresh, nil, &mid, map[string]any{
"module_id": moduleID,
"trigger": trigger,
})
}
func (s *Server) handleGetRevision(w http.ResponseWriter, r *http.Request) {
a, ok := authFromContext(r.Context())
if !ok {
+9 -3
View File
@@ -400,11 +400,13 @@ func (s *Server) handlePostIPRange(w http.ResponseWriter, r *http.Request) {
writeProblem(w, http.StatusBadRequest, "Bad Request", "invalid json")
return
}
x, err := s.store.CreateIPRangeEntry(a.TenantID, r.PathValue("module_id"), &body)
mid := r.PathValue("module_id")
x, err := s.store.CreateIPRangeEntry(a.TenantID, mid, &body)
if err != nil {
writeStoreErr(w, err)
return
}
s.enqueueModuleRefreshIfEnabled(a.TenantID, mid, "ip_range_create")
writeJSON(w, http.StatusCreated, ipRangeJSON(x))
}
@@ -418,11 +420,13 @@ func (s *Server) handlePatchIPRange(w http.ResponseWriter, r *http.Request) {
writeProblem(w, http.StatusBadRequest, "Bad Request", "invalid json")
return
}
x, err := s.store.UpdateIPRangeEntry(a.TenantID, r.PathValue("module_id"), r.PathValue("entry_id"), &body)
mid := r.PathValue("module_id")
x, err := s.store.UpdateIPRangeEntry(a.TenantID, mid, r.PathValue("entry_id"), &body)
if err != nil {
writeStoreErr(w, err)
return
}
s.enqueueModuleRefreshIfEnabled(a.TenantID, mid, "ip_range_patch")
writeJSON(w, http.StatusOK, ipRangeJSON(x))
}
@@ -431,10 +435,12 @@ func (s *Server) handleDeleteIPRange(w http.ResponseWriter, r *http.Request) {
if !ok || !s.requireAtLeast(w, a, "editor") {
return
}
if err := s.store.DeleteIPRangeEntry(a.TenantID, r.PathValue("module_id"), r.PathValue("entry_id")); err != nil {
mid := r.PathValue("module_id")
if err := s.store.DeleteIPRangeEntry(a.TenantID, mid, r.PathValue("entry_id")); err != nil {
writeStoreErr(w, err)
return
}
s.enqueueModuleRefreshIfEnabled(a.TenantID, mid, "ip_range_delete")
w.WriteHeader(http.StatusNoContent)
}
+9 -2
View File
@@ -68,7 +68,7 @@ func TestAPIRefreshApplyJobsBundle(t *testing.T) {
}
})
t.Run("refresh IP_RANGES no op", func(t *testing.T) {
t.Run("refresh IP_RANGES queues render job", func(t *testing.T) {
req, _ := http.NewRequest(http.MethodPost, base+"/v1/modules/"+modIP+"/refresh", nil)
req.Header.Set("Authorization", "Bearer opkey")
resp, err := client.Do(req)
@@ -76,10 +76,17 @@ func TestAPIRefreshApplyJobsBundle(t *testing.T) {
t.Fatal(err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusNoContent {
if resp.StatusCode != http.StatusAccepted {
b, _ := io.ReadAll(resp.Body)
t.Fatalf("status %d: %s", resp.StatusCode, b)
}
var body struct {
JobID string `json:"job_id"`
}
if err := json.NewDecoder(resp.Body).Decode(&body); err != nil {
t.Fatal(err)
}
waitJob(t, client, base, "opkey", body.JobID)
})
t.Run("refresh CDN queues job", func(t *testing.T) {