feat(pipeline): use stale snapshot when upstream fetch fails
При ошибке CDN/ASN/DoH ingest использует последний снимок префиксов (или просроченный ASN-кэш), если EVOBGP_STALE_ON_UPSTREAM_ERROR не равен 0. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
package pipeline
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/netip"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"evobgp/internal/store"
|
||||
)
|
||||
|
||||
// staleOnUpstreamError reports whether ingest should keep last-known prefixes when an upstream fetch fails.
|
||||
// Enabled by default; set EVOBGP_STALE_ON_UPSTREAM_ERROR=0 to restore fail-fast behavior.
|
||||
func staleOnUpstreamError() bool {
|
||||
v := strings.TrimSpace(os.Getenv("EVOBGP_STALE_ON_UPSTREAM_ERROR"))
|
||||
if v == "" || v == "1" || strings.EqualFold(v, "true") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func logStaleUpstream(kind, detail string) {
|
||||
log.Printf("pipeline: stale upstream fallback (%s): %s", kind, detail)
|
||||
}
|
||||
|
||||
func staleASNPrefixes(st store.Backend, priorSnapshot []store.PrefixRow, asn int64) ([]store.PrefixRow, string, bool) {
|
||||
sourceKey := fmt.Sprintf("as:%d", asn)
|
||||
if cached := prefixRowsForSource(priorSnapshot, sourceKey); len(cached) > 0 {
|
||||
return cached, "", true
|
||||
}
|
||||
if st == nil {
|
||||
return nil, "", false
|
||||
}
|
||||
ent, ok, err := st.GetASNPrefixCache(asn)
|
||||
if err != nil || !ok || ent == nil || len(ent.Prefixes) == 0 {
|
||||
return nil, "", false
|
||||
}
|
||||
var rows []store.PrefixRow
|
||||
for _, p := range ent.Prefixes {
|
||||
pfx, perr := netip.ParsePrefix(strings.TrimSpace(p))
|
||||
if perr != nil {
|
||||
continue
|
||||
}
|
||||
rows = append(rows, store.PrefixRow{Prefix: pfx.Masked().String(), Source: sourceKey})
|
||||
}
|
||||
if len(rows) == 0 {
|
||||
return nil, "", false
|
||||
}
|
||||
return rows, ent.Holder, true
|
||||
}
|
||||
|
||||
func staleDomainPrefixes(priorSnapshot []store.PrefixRow, fqdn string) ([]store.PrefixRow, bool) {
|
||||
sourceKey := "domain:" + strings.TrimSpace(fqdn)
|
||||
cached := prefixRowsForSource(priorSnapshot, sourceKey)
|
||||
return cached, len(cached) > 0
|
||||
}
|
||||
|
||||
func staleCDNPrefixes(st store.Backend, tenantID, moduleID string, priorSnapshot []store.PrefixRow, sourceID string) ([]store.PrefixRow, bool) {
|
||||
sourceKey := cdnSourceKey(sourceID)
|
||||
cached := cachedCDNPrefixRows(st, tenantID, moduleID, priorSnapshot, sourceKey)
|
||||
return cached, len(cached) > 0
|
||||
}
|
||||
|
||||
// asnCacheExpired returns cached ASN prefixes even past TTL (for stale fallback only).
|
||||
func asnCacheExpired(st store.Backend, asn int64) ([]netip.Prefix, string, bool) {
|
||||
if st == nil {
|
||||
return nil, "", false
|
||||
}
|
||||
ent, ok, err := st.GetASNPrefixCache(asn)
|
||||
if err != nil || !ok || ent == nil || len(ent.Prefixes) == 0 {
|
||||
return nil, "", false
|
||||
}
|
||||
out := make([]netip.Prefix, 0, len(ent.Prefixes))
|
||||
for _, p := range ent.Prefixes {
|
||||
pfx, perr := netip.ParsePrefix(strings.TrimSpace(p))
|
||||
if perr != nil {
|
||||
continue
|
||||
}
|
||||
out = append(out, pfx.Masked())
|
||||
}
|
||||
if len(out) == 0 {
|
||||
return nil, "", false
|
||||
}
|
||||
return out, ent.Holder, true
|
||||
}
|
||||
Reference in New Issue
Block a user