mirror of
https://github.com/akvorado/akvorado.git
synced 2025-12-11 22:14:02 +01:00
When shutting down the outlet, the core component is first shutdown, and only after that Kafka and ClickHouse. This means we were still consuming messages from Kafka and throwing them away. Instead, let the core component stop the Kafka workers before shutting down itself. Fix #2100
108 lines
2.8 KiB
Go
108 lines
2.8 KiB
Go
// SPDX-FileCopyrightText: 2022 Free Mobile
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
// Package core plumbs all the other components together.
|
|
package core
|
|
|
|
import (
|
|
"time"
|
|
|
|
"gopkg.in/tomb.v2"
|
|
|
|
"akvorado/common/daemon"
|
|
"akvorado/common/helpers/cache"
|
|
"akvorado/common/httpserver"
|
|
"akvorado/common/reporter"
|
|
"akvorado/common/schema"
|
|
"akvorado/outlet/clickhouse"
|
|
"akvorado/outlet/flow"
|
|
"akvorado/outlet/kafka"
|
|
"akvorado/outlet/metadata"
|
|
"akvorado/outlet/routing"
|
|
)
|
|
|
|
// Component represents the HTTP compomenent.
|
|
type Component struct {
|
|
r *reporter.Reporter
|
|
d *Dependencies
|
|
t tomb.Tomb
|
|
config Configuration
|
|
|
|
metrics metrics
|
|
|
|
httpFlowClients uint32 // for dumping flows
|
|
httpFlowChannel chan []byte
|
|
httpFlowFlushDelay time.Duration
|
|
|
|
classifierExporterCache *cache.Cache[exporterInfo, exporterClassification]
|
|
classifierInterfaceCache *cache.Cache[exporterAndInterfaceInfo, interfaceClassification]
|
|
classifierErrLogger reporter.Logger
|
|
}
|
|
|
|
// Dependencies define the dependencies of the HTTP component.
|
|
type Dependencies struct {
|
|
Daemon daemon.Component
|
|
Flow *flow.Component
|
|
Metadata *metadata.Component
|
|
Routing *routing.Component
|
|
Kafka kafka.Component
|
|
ClickHouse clickhouse.Component
|
|
HTTP *httpserver.Component
|
|
Schema *schema.Component
|
|
}
|
|
|
|
// New creates a new core component.
|
|
func New(r *reporter.Reporter, configuration Configuration, dependencies Dependencies) (*Component, error) {
|
|
c := Component{
|
|
r: r,
|
|
d: &dependencies,
|
|
config: configuration,
|
|
|
|
httpFlowClients: 0,
|
|
httpFlowChannel: make(chan []byte, 10),
|
|
httpFlowFlushDelay: time.Second,
|
|
|
|
classifierExporterCache: cache.New[exporterInfo, exporterClassification](),
|
|
classifierInterfaceCache: cache.New[exporterAndInterfaceInfo, interfaceClassification](),
|
|
classifierErrLogger: r.Sample(reporter.BurstSampler(10*time.Second, 3)),
|
|
}
|
|
c.d.Daemon.Track(&c.t, "outlet/core")
|
|
c.initMetrics()
|
|
return &c, nil
|
|
}
|
|
|
|
// Start starts the core component.
|
|
func (c *Component) Start() error {
|
|
c.r.Info().Msg("starting core component")
|
|
c.d.Kafka.StartWorkers(c.newWorker)
|
|
|
|
// Classifier cache expiration
|
|
c.t.Go(func() error {
|
|
for {
|
|
select {
|
|
case <-c.t.Dying():
|
|
return nil
|
|
case <-time.After(c.config.ClassifierCacheDuration):
|
|
before := time.Now().Add(-c.config.ClassifierCacheDuration)
|
|
c.classifierExporterCache.DeleteLastAccessedBefore(before)
|
|
c.classifierInterfaceCache.DeleteLastAccessedBefore(before)
|
|
}
|
|
}
|
|
})
|
|
|
|
c.d.HTTP.GinRouter.GET("/api/v0/outlet/flows", c.FlowsHTTPHandler)
|
|
return nil
|
|
}
|
|
|
|
// Stop stops the core component.
|
|
func (c *Component) Stop() error {
|
|
defer func() {
|
|
close(c.httpFlowChannel)
|
|
c.r.Info().Msg("core component stopped")
|
|
}()
|
|
c.r.Info().Msg("stopping core component")
|
|
c.d.Kafka.StopWorkers()
|
|
c.t.Kill(nil)
|
|
return c.t.Wait()
|
|
}
|