fix: log returns as soon as the QSO row is inserted; award_refs/recording/uploads/eQSL now run off the critical path (both manual and UDP) — a busy multi-op MySQL no longer freezes the entry form ~40s waiting on the award_refs UPDATE
This commit is contained in:
@@ -1948,25 +1948,36 @@ func (a *App) AddQSO(q qso.QSO) (id int64, err error) {
|
||||
}
|
||||
if err == nil {
|
||||
q.ID = id
|
||||
a.noteWorked(q.Callsign, q.Band, q.Mode) // keep the alert worked-index fresh
|
||||
a.noteLiveQSO() // multi-op: flip this operator back "online"
|
||||
a.materializeAwardRefs(q) // stamp award_refs so the grid columns show at once
|
||||
// Announce the log so UI widgets can react (e.g. the Flex panel zeroing RIT).
|
||||
a.noteWorked(q.Callsign, q.Band, q.Mode) // keep the alert worked-index fresh (in-memory)
|
||||
a.noteLiveQSO() // multi-op: flip this operator back "online" (publishes async)
|
||||
// Announce the log RIGHT AWAY so the grid/UI refresh at once and the entry
|
||||
// form clears immediately — the operator is not made to wait on the DB.
|
||||
wruntime.EventsEmit(a.ctx, "qso:logged", id)
|
||||
a.saveQSORecording(&q)
|
||||
if a.extsvc != nil {
|
||||
a.extsvc.OnQSOLogged(id)
|
||||
}
|
||||
a.maybeAutoSendEQSL(q)
|
||||
// Forward the ADIF of this QSO to any outbound "ADIF message" UDP rows.
|
||||
if a.udp != nil {
|
||||
go a.udp.EmitLoggedADIF(adif.SingleRecordADIF(q))
|
||||
}
|
||||
// A successful write means the link is healthy again — if QSOs are still
|
||||
// parked, get them in now rather than waiting for the next tick.
|
||||
if a.offlineMode && a.offlineQ != nil && a.offlineQ.Count() > 0 {
|
||||
go func() { _, _ = a.replayOfflineQueue() }()
|
||||
}
|
||||
// Everything below writes to (or reads from) the shared DB. Run it OFF the
|
||||
// critical path: on a busy multi-op MySQL the award_refs UPDATE alone could
|
||||
// block ~40s (and hit "Too many connections"), which used to freeze the log
|
||||
// (form stuck, "…" on the button) until it finished. The QSO row is already
|
||||
// safely inserted; these just enrich it, so they can lag a beat.
|
||||
qc := q
|
||||
go func() {
|
||||
a.materializeAwardRefs(qc) // fills the award_refs column
|
||||
a.saveQSORecording(&qc)
|
||||
if a.extsvc != nil {
|
||||
a.extsvc.OnQSOLogged(id)
|
||||
}
|
||||
a.maybeAutoSendEQSL(qc)
|
||||
if a.udp != nil {
|
||||
a.udp.EmitLoggedADIF(adif.SingleRecordADIF(qc))
|
||||
}
|
||||
// Nudge the grid again so the award_refs columns appear once materialised.
|
||||
if a.ctx != nil {
|
||||
wruntime.EventsEmit(a.ctx, "qso:logged", id)
|
||||
}
|
||||
// A successful write means the link is healthy — flush any parked QSOs.
|
||||
if a.offlineMode && a.offlineQ != nil && a.offlineQ.Count() > 0 {
|
||||
_, _ = a.replayOfflineQueue()
|
||||
}
|
||||
}()
|
||||
}
|
||||
return id, err
|
||||
}
|
||||
@@ -9634,24 +9645,28 @@ func (a *App) LogUDPLoggedADIF(adifText string) (int64, error) {
|
||||
return 0, fmt.Errorf("insert qso: %w", err)
|
||||
}
|
||||
q.ID = id
|
||||
a.noteLiveQSO() // multi-op: flip this operator back "online"
|
||||
a.materializeAwardRefs(q)
|
||||
// Announce the log so UI widgets refresh AT ONCE (the Recent-QSOs grid, the
|
||||
// ON-AIR badge and the "stations on air" widget). The manual log path always
|
||||
// did this; the UDP/FT8 path did not, so a station running MSHV saw the top
|
||||
// "on air" list lag ~15-45s behind the instant bottom badge.
|
||||
a.noteLiveQSO() // multi-op: flip this operator back "online" (publishes async)
|
||||
// Announce the log AT ONCE so the grid / ON-AIR badge / stations-on-air widget
|
||||
// refresh immediately, then run the DB-heavy enrichment off the critical path
|
||||
// (same reasoning as the manual path — award_refs on a busy shared MySQL blocked).
|
||||
if a.ctx != nil {
|
||||
wruntime.EventsEmit(a.ctx, "qso:logged", id)
|
||||
}
|
||||
a.saveQSORecording(&q)
|
||||
if a.extsvc != nil {
|
||||
a.extsvc.OnQSOLogged(id)
|
||||
}
|
||||
a.maybeAutoSendEQSL(q)
|
||||
// A successful write means the link is healthy again — flush anything parked.
|
||||
if a.offlineMode && a.offlineQ != nil && a.offlineQ.Count() > 0 {
|
||||
go func() { _, _ = a.replayOfflineQueue() }()
|
||||
}
|
||||
qc := q
|
||||
go func() {
|
||||
a.materializeAwardRefs(qc)
|
||||
a.saveQSORecording(&qc)
|
||||
if a.extsvc != nil {
|
||||
a.extsvc.OnQSOLogged(id)
|
||||
}
|
||||
a.maybeAutoSendEQSL(qc)
|
||||
if a.ctx != nil {
|
||||
wruntime.EventsEmit(a.ctx, "qso:logged", id) // refresh again so award_refs show
|
||||
}
|
||||
if a.offlineMode && a.offlineQ != nil && a.offlineQ.Count() > 0 {
|
||||
_, _ = a.replayOfflineQueue()
|
||||
}
|
||||
}()
|
||||
return id, nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user