improved some of the tasks to use fewer goroutines

This commit is contained in:
2025-10-04 13:56:30 -06:00
parent 445f50a5c0
commit c7f5c57e82
5 changed files with 77 additions and 32 deletions
+34
View File
@@ -12,6 +12,8 @@ package database
import ( import (
"fmt" "fmt"
"time" "time"
"github.com/labstack/gommon/log"
) )
// AuditRecord holds an audit record instance. // AuditRecord holds an audit record instance.
@@ -46,6 +48,9 @@ const (
AuditAdminLockUnlockAccount = 113 AuditAdminLockUnlockAccount = 113
) )
// auditWriteQueue is a channel to store audit records in the background.
var auditWriteQueue chan *AuditRecord
/* AmNewAudit creates a new audit record. /* AmNewAudit creates a new audit record.
* Parameters: * Parameters:
* rectype - Audit record type. * rectype - Audit record type.
@@ -94,3 +99,32 @@ func (ar *AuditRecord) Store() error {
ar.OnDate = moment ar.OnDate = moment
return nil return nil
} }
// auditWriter is the routine that stores audit records in trhe background.
func auditWriter(workChan chan *AuditRecord, doneChan chan bool) {
for ar := range workChan {
err := ar.Store()
if err != nil {
log.Errorf("dropped audit record on the floor: %v", err)
}
}
doneChan <- true
}
// AmStoreAudit stores the audit record in the background.
func AmStoreAudit(rec *AuditRecord) {
if rec != nil {
auditWriteQueue <- rec
}
}
// setupAuditWriter sets up the background audit writer.
func setupAuditWriter() func() {
auditWriteQueue = make(chan *AuditRecord, 16)
doneChan := make(chan bool)
go auditWriter(auditWriteQueue, doneChan)
return func() {
close(auditWriteQueue)
<-doneChan
}
}
+5 -1
View File
@@ -20,12 +20,16 @@ var amdb *sqlx.DB
// SetupDb sets up the database and associated items. // SetupDb sets up the database and associated items.
func SetupDb() (func(), error) { func SetupDb() (func(), error) {
var fn1 func() = nil
db, err := sqlx.Open(config.GlobalConfig.Database.Driver, config.GlobalConfig.Database.Dsn) db, err := sqlx.Open(config.GlobalConfig.Database.Driver, config.GlobalConfig.Database.Dsn)
if err == nil { if err == nil {
amdb = db amdb = db
// TODO: additional initialization fn1 = setupAuditWriter()
} }
return func() { return func() {
if fn1 != nil {
fn1()
}
amdb.Close() amdb.Close()
}, err }, err
} }
+2 -6
View File
@@ -226,9 +226,7 @@ func AmAuthenticateUser(name string, password string, remoteIP string) (*User, e
log.Debugf("AmAuthenicate() authenticating user %s...", name) log.Debugf("AmAuthenicate() authenticating user %s...", name)
var ar *AuditRecord = nil var ar *AuditRecord = nil
defer func() { defer func() {
if ar != nil { AmStoreAudit(ar)
go ar.Store()
}
}() }()
user, err := AmGetUserByName(name) user, err := AmGetUserByName(name)
@@ -294,9 +292,7 @@ func crackAuthString(authString string) (int32, string, error) {
func AmAuthenticateUserByToken(authString string, remoteIP string) (*User, error) { func AmAuthenticateUserByToken(authString string, remoteIP string) (*User, error) {
var ar *AuditRecord = nil var ar *AuditRecord = nil
defer func() { defer func() {
if ar != nil { AmStoreAudit(ar)
go ar.Store()
}
}() }()
uid, token, err := crackAuthString(authString) uid, token, err := crackAuthString(authString)
+23 -17
View File
@@ -131,22 +131,28 @@ func AmNewEmailMessage(sender int32, ip string) Message {
return rc return rc
} }
// recycleMessage cleans out a message and puts it back on the free list. // The "recycle bin" for messages.
func recycleMessage(m *amMessage) { var messageRecycleBin chan *amMessage
m.from = ""
m.fromAddr = "" // recycleMessages is a goroutine that recycles the messages on its queue.
m.to = make([]string, 0) func recycleMessages(messages chan *amMessage, done chan bool) {
m.toAddrs = make([]string, 0) for m := range messages {
m.cc = make([]string, 0) m.from = ""
m.bcc = make([]string, 0) m.fromAddr = ""
m.subject = "" m.to = make([]string, 0)
m.text = "" m.toAddrs = make([]string, 0)
for k := range m.headers { m.cc = make([]string, 0)
delete(m.headers, k) m.bcc = make([]string, 0)
m.subject = ""
m.text = ""
for k := range m.headers {
delete(m.headers, k)
}
m.template = ""
for k := range m.vars {
delete(m.vars, k)
}
freeMessages.Put(m)
} }
m.template = "" done <- true
for k := range m.vars {
delete(m.vars, k)
}
freeMessages.Put(m)
} }
+13 -8
View File
@@ -174,7 +174,7 @@ func senderLoop(sent chan *amMessage, done chan bool) {
} else { } else {
log.Errorf("unable to format message: %v", err) log.Errorf("unable to format message: %v", err)
} }
go recycleMessage(m) messageRecycleBin <- m
} }
done <- true // signal done for synchronization done <- true // signal done for synchronization
} }
@@ -182,9 +182,6 @@ func senderLoop(sent chan *amMessage, done chan bool) {
// sendChan is the channel we put E-mail messages on to be sent. // sendChan is the channel we put E-mail messages on to be sent.
var sendChan chan *amMessage var sendChan chan *amMessage
// doneChan is the channel that gets signaled when the senderLoop breaks.
var doneChan chan bool
// SetupMailSender starts the mail-sending goroutine. // SetupMailSender starts the mail-sending goroutine.
func SetupMailSender() func() { func SetupMailSender() func() {
// Initialize mail host and authentication. // Initialize mail host and authentication.
@@ -207,12 +204,20 @@ func SetupMailSender() func() {
jet.DevelopmentMode(true), jet.DevelopmentMode(true),
) )
// Start the recycler.
messageRecycleBin = make(chan *amMessage, 16)
doneChan1 := make(chan bool)
go recycleMessages(messageRecycleBin, doneChan1)
// Start the sender loop. // Start the sender loop.
sendChan = make(chan *amMessage, 16) sendChan = make(chan *amMessage, 16)
doneChan = make(chan bool) doneChan2 := make(chan bool)
go senderLoop(sendChan, doneChan) go senderLoop(sendChan, doneChan2)
return func() { return func() {
close(sendChan) // will break the loop in senderLoop close(sendChan)
<-doneChan // wait for routine to complete <-doneChan2
close(messageRecycleBin)
<-doneChan1
} }
} }