fix: отмена скана при исчерпании соединений Postgres
- Распознавание 53300/too many clients и др. в isStoreCapacityOrConnExhausted - SaveHostResult/порты/SNMP: при фатальной ошибке БД — CancelScan; ctx отменяет дальнейший SNMP - Воркеры при ctx.Done быстро скипают оставшиеся IP без SNMP (дренаж канала) Made-with: Cursor
This commit is contained in:
+56
-18
@@ -174,6 +174,16 @@ func (r *Runner) run(ctx context.Context, job ScanJob) {
|
||||
const minProgressWriteInterval = 500 * time.Millisecond
|
||||
var progWriteMu sync.Mutex
|
||||
var lastProgressWrite time.Time
|
||||
var storeFatalOnce sync.Once
|
||||
storeAbortIfFatal := func(op string, err error) {
|
||||
if err == nil || !isStoreCapacityOrConnExhausted(err) {
|
||||
return
|
||||
}
|
||||
storeFatalOnce.Do(func() {
|
||||
log.Printf("scan %s: критическая ошибка БД (%s): %v — отмена скана", job.ID, op, err)
|
||||
r.CancelScan(job.ID)
|
||||
})
|
||||
}
|
||||
|
||||
pushProgress := func(force bool) {
|
||||
mu.Lock()
|
||||
@@ -207,21 +217,34 @@ func (r *Runner) run(ctx context.Context, job ScanJob) {
|
||||
worker := func() {
|
||||
defer wg.Done()
|
||||
for ip := range workCh {
|
||||
if ctx.Err() != nil {
|
||||
continue
|
||||
}
|
||||
isUp := probeHost(ip, job.Options.PingTimeoutMS)
|
||||
checkedAt := time.Now().UTC()
|
||||
_ = r.store.SaveHostResult(job.ID, HostResult{
|
||||
if err := r.store.SaveHostResult(job.ID, HostResult{
|
||||
IP: ip,
|
||||
IsUp: isUp,
|
||||
CheckedAt: checkedAt,
|
||||
})
|
||||
if isUp && job.Options.PortScanEnabled {
|
||||
}); err != nil {
|
||||
storeAbortIfFatal("SaveHostResult", err)
|
||||
if !isStoreCapacityOrConnExhausted(err) {
|
||||
log.Printf("scan %s: SaveHostResult %s: %v", job.ID, ip, err)
|
||||
}
|
||||
} else if isUp && job.Options.PortScanEnabled {
|
||||
for _, p := range job.Options.Ports {
|
||||
_ = r.store.SaveOpenPortResult(job.ID, OpenPortResult{
|
||||
if err := r.store.SaveOpenPortResult(job.ID, OpenPortResult{
|
||||
IP: ip,
|
||||
Port: p,
|
||||
IsOpen: probeTCPPort(ip, p, job.Options.PingTimeoutMS),
|
||||
CheckedAt: checkedAt,
|
||||
})
|
||||
}); err != nil {
|
||||
storeAbortIfFatal("SaveOpenPortResult", err)
|
||||
if !isStoreCapacityOrConnExhausted(err) {
|
||||
log.Printf("scan %s: SaveOpenPortResult %s:%d: %v", job.ID, ip, p, err)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,22 +256,37 @@ func (r *Runner) run(ctx context.Context, job ScanJob) {
|
||||
mu.Unlock()
|
||||
pushProgress(false)
|
||||
|
||||
if isUp && r.cfg.SNMPEnabled {
|
||||
if isUp && r.cfg.SNMPEnabled && ctx.Err() == nil {
|
||||
snmpRes, lldpRes, ifRes, portDevRes := probeSNMPAndLLDP(ip, r.cfg.SNMPCommunity, checkedAt, job.Options.PingTimeoutMS)
|
||||
_ = r.store.SaveSNMPResult(job.ID, snmpRes)
|
||||
for _, lr := range lldpRes {
|
||||
if err := r.store.SaveLLDPResult(job.ID, lr); err != nil {
|
||||
log.Printf("scan %s: save LLDP для %s: %v", job.ID, lr.IP, err)
|
||||
if err := r.store.SaveSNMPResult(job.ID, snmpRes); err != nil {
|
||||
storeAbortIfFatal("SaveSNMPResult", err)
|
||||
if !isStoreCapacityOrConnExhausted(err) {
|
||||
log.Printf("scan %s: SaveSNMPResult %s: %v", job.ID, ip, err)
|
||||
}
|
||||
}
|
||||
for _, iface := range ifRes {
|
||||
if err := r.store.SaveInterfaceResult(job.ID, iface); err != nil {
|
||||
log.Printf("scan %s: save interface %s ifIndex=%d: %v", job.ID, iface.IP, iface.IfIndex, err)
|
||||
} else {
|
||||
for _, lr := range lldpRes {
|
||||
if err := r.store.SaveLLDPResult(job.ID, lr); err != nil {
|
||||
storeAbortIfFatal("SaveLLDPResult", err)
|
||||
if !isStoreCapacityOrConnExhausted(err) {
|
||||
log.Printf("scan %s: save LLDP для %s: %v", job.ID, lr.IP, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, pd := range portDevRes {
|
||||
if err := r.store.SavePortDeviceResult(job.ID, pd); err != nil {
|
||||
log.Printf("scan %s: save port-device %s ifIndex=%d mac=%s: %v", job.ID, pd.IP, pd.IfIndex, pd.MAC, err)
|
||||
for _, iface := range ifRes {
|
||||
if err := r.store.SaveInterfaceResult(job.ID, iface); err != nil {
|
||||
storeAbortIfFatal("SaveInterfaceResult", err)
|
||||
if !isStoreCapacityOrConnExhausted(err) {
|
||||
log.Printf("scan %s: save interface %s ifIndex=%d: %v", job.ID, iface.IP, iface.IfIndex, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, pd := range portDevRes {
|
||||
if err := r.store.SavePortDeviceResult(job.ID, pd); err != nil {
|
||||
storeAbortIfFatal("SavePortDeviceResult", err)
|
||||
if !isStoreCapacityOrConnExhausted(err) {
|
||||
log.Printf("scan %s: save port-device %s ifIndex=%d mac=%s: %v", job.ID, pd.IP, pd.IfIndex, pd.MAC, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user