Repository navigation
Closed
Labels
Prio MediumsuggestionSuggestions on how to improve the projectSuggestions on how to improve the project
Description
- JSONLite, JSON, JSONDomains are computed for each entry without checking if current clients need them
- most installations of certstream server-go would use a single client with a single subscription type (same client cannot have multiple subscription types as per config)
- I believe there would be non trivial amount of savings in CPU if we switch to computing bytes only for the subscription types that are actually needed
certstream-server-go/internal/broadcast/dispatcher.go
Lines 120 to 151 in 6ae7d17
| func (bm *Dispatcher) broadcaster() { | |
| for { | |
| var data []byte | |
| // Take entry out of broadcast channel and generate JSON representations for the entry. | |
| entry := <-bm.MessageQueue | |
| dataLite := entry.JSONLite() | |
| dataFull := entry.JSON() | |
| dataDomain := entry.JSONDomains() | |
| bm.clientLock.RLock() | |
| for _, c := range bm.clients { | |
| switch c.SubType() { | |
| case SubTypeLite: | |
| data = dataLite | |
| case SubTypeFull: | |
| data = dataFull | |
| case SubTypeDomain: | |
| data = dataDomain | |
| default: | |
| // This should never happen, but if it does, we log it and skip the client. | |
| log.Printf("Unknown subscription type '%d' for client '%s'. Skipping this client!\n", c.SubType(), c.Name()) | |
| continue | |
| } | |
| c.Write(data) | |
| } | |
| bm.clientLock.RUnlock() | |
| } | |
| } |
A updated version of this code would look like:
// broadcaster is run in a goroutine and handles the dispatching of certs to clients.
func (bm *Dispatcher) broadcaster() {
for {
// Take entry out of broadcast channel and generate JSON representations for the entry.
entry := <-bm.MessageQueue
computeBytes := entryByteComputer(&entry)
bm.clientLock.RLock()
for _, c := range bm.clients {
data, err := computeBytes(c.SubType())
// This should never happen, but if it does, we log it and skip the client.
if err != nil {
log.Printf("%s on client '%s'. Skipping this client!\n", err.Error(), c.Name())
continue
}
c.Write(data)
}
bm.clientLock.RUnlock()
}
}
// Compute and cache bytes as per necessity
func entryByteComputer(entry *models.Entry) func(subType SubscriptionType) ([]byte, error) {
dataLite := []byte{}
isDataLiteComputed := false
dataFull := []byte{}
isDataFullComputed := false
dataDomain := []byte{}
isDataDomainComputed := false
return func(subType SubscriptionType) ([]byte, error) {
switch subType {
case SubTypeLite:
if !isDataLiteComputed {
dataLite = entry.JSONLite()
isDataLiteComputed = true
}
return dataLite, nil
case SubTypeFull:
if !isDataFullComputed {
dataFull = entry.JSON()
isDataFullComputed = true
}
return dataFull, nil
case SubTypeDomain:
if !isDataDomainComputed {
dataDomain = entry.JSONDomains()
isDataDomainComputed = true
}
return dataDomain, nil
default:
return []byte{}, fmt.Errorf("Unknown subscription type '%d'", subType)
}
}
}
Metadata
Metadata
Assignees
Labels
Prio MediumsuggestionSuggestions on how to improve the projectSuggestions on how to improve the project
Activity
messede-degod commentedon Sep 23, 2026
PR made here: #128
d-Rickyy-b commentedon Sep 25, 2026
Thanks for the reasonable suggestion. It's definitely smart to not calculate the JSON when there is no client connected at all or when the connected client does not need any of the other two types.
I think your current suggestion on how to implement this is not quite the way I would have implemented it. I will discuss the details via comments to your PR later.
Merge pull request #128 from messede-degod/fix/optimize-brodcaster
messede-degod commentedon Sep 27, 2026
Fixed by: #128