fix: serialise UDP QSO logging (lookup+dedup+insert) so multi-stream MSHV (4 QSOs at once) queues instead of firing concurrent lookups/DB writes that got 'too many requests'
This commit is contained in:
@@ -9455,6 +9455,15 @@ func (a *App) LogUDPLoggedADIF(adifText string) (int64, error) {
|
|||||||
if a.qso == nil {
|
if a.qso == nil {
|
||||||
return 0, fmt.Errorf("db not initialized")
|
return 0, fmt.Errorf("db not initialized")
|
||||||
}
|
}
|
||||||
|
// Serialise the WHOLE operation — parse, callsign LOOKUP, dedup and insert —
|
||||||
|
// so simultaneous UDP QSOs are processed one at a time (a queue). A multi-stream
|
||||||
|
// MSHV finishing 4 QSOs at once used to fire 4 concurrent callsign lookups and DB
|
||||||
|
// writes, which the QRZ/HamQTH service (and a remote DB) rejected with "too many
|
||||||
|
// requests". Holding the lock across the lookup spaces them out; the UDP reader
|
||||||
|
// runs on its own goroutine, so this never blocks packet reception — callers just
|
||||||
|
// queue behind each other. (adifwatch shares this lock for the same reason.)
|
||||||
|
a.udpLogMu.Lock()
|
||||||
|
defer a.udpLogMu.Unlock()
|
||||||
// Pull the first record out of the payload. WSJT-X / JTDX / MSHV
|
// Pull the first record out of the payload. WSJT-X / JTDX / MSHV
|
||||||
// always send a single QSO per UDP packet (no header) but we tolerate
|
// always send a single QSO per UDP packet (no header) but we tolerate
|
||||||
// either form via adif.Parse.
|
// either form via adif.Parse.
|
||||||
@@ -9597,12 +9606,10 @@ func (a *App) LogUDPLoggedADIF(adifText string) (int64, error) {
|
|||||||
// a minute (the two apps stamp their own time), so a minute-exact key
|
// a minute (the two apps stamp their own time), so a minute-exact key
|
||||||
// missed it and the contact got duplicated.
|
// missed it and the contact got duplicated.
|
||||||
//
|
//
|
||||||
// The check + insert is guarded by udpLogMu: MSHV/WSJT can deliver the same
|
// The check + insert is covered by udpLogMu (taken at the top of this function):
|
||||||
// logged-QSO packet twice in quick succession (re-broadcast, or two
|
// MSHV/WSJT can deliver the same logged-QSO packet twice in quick succession
|
||||||
// listeners), and without serialisation both goroutines read the dedup set
|
// (re-broadcast, or two listeners), and without serialisation both goroutines
|
||||||
// BEFORE either inserts, both pass, and the QSO lands twice.
|
// read the dedup set BEFORE either inserts, both pass, and the QSO lands twice.
|
||||||
a.udpLogMu.Lock()
|
|
||||||
defer a.udpLogMu.Unlock()
|
|
||||||
seen, err := a.qso.ExistingDedupeKeys(a.ctx)
|
seen, err := a.qso.ExistingDedupeKeys(a.ctx)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
base := q.QSODate.UTC()
|
base := q.QSODate.UTC()
|
||||||
|
|||||||
Reference in New Issue
Block a user