mirror of
https://github.com/hanzoai/tasks.git
synced 2026-11-03 03:56:04 +00:00
## What changed?
<!-- Describe what has changed in this PR -->
Remove license header from every file. Because it is really hard to
follow in this PR here is the summary:
1. License header is removed from all `.go` and `.proto` files
:fireworks::fireworks:🎆.
2. `LICENSE` file in the root directory has only Temporal and Uber
copyrights.
3. 5 other `LICENSE` files added to the packages which have copyrights
different from Temporal and Uber: Datadog, Xargin, "Mat Ryer, Tyler
Bunnell and contributors".
4. `license_file` flag is removed from all code generation tools.
5. `copyright_file` flag is removed from `go:generate mockgen`
directive.
6. All copyright related targets are removed from `Makefile`.
7. Updated Temporal copyright year to 2025 everywhere.
## Why?
<!-- Tell your future self why have you made these changes -->
I double checked with legal department that it is not needed to have
license header in every file. One file per repo is enough. I put all
copyrights to the root `LICENSE` file and removed header from all other
files. Also updated tools and `Makefile`.
189 lines
4.5 KiB
Go
189 lines
4.5 KiB
Go
package queues
|
|
|
|
import (
|
|
"sync"
|
|
"sync/atomic"
|
|
"time"
|
|
|
|
"go.temporal.io/server/common"
|
|
"go.temporal.io/server/common/clock"
|
|
"go.temporal.io/server/common/metrics"
|
|
"go.temporal.io/server/common/namespace"
|
|
)
|
|
|
|
var noopScheduleMonitor = &noopSchedulerMonitor{}
|
|
|
|
var defaultSchedulerMonitorOptions = schedulerMonitorOptions{
|
|
aggregationCount: 100,
|
|
aggregationDuration: time.Second * 30,
|
|
}
|
|
|
|
type (
|
|
schedulerMonitor struct {
|
|
taskChannelKeyFn TaskChannelKeyFn
|
|
namespaceRegistry namespace.Registry
|
|
timeSource clock.TimeSource
|
|
metricsHandler metrics.Handler
|
|
options schedulerMonitorOptions
|
|
|
|
status int32
|
|
shutdownCh chan struct{}
|
|
|
|
sync.Mutex
|
|
scheduleStats map[TaskChannelKey]*scheduleStats
|
|
}
|
|
|
|
schedulerMonitorOptions struct {
|
|
aggregationCount int
|
|
aggregationDuration time.Duration
|
|
}
|
|
|
|
scheduleStats struct {
|
|
lastStartTime time.Time
|
|
totalLatency time.Duration
|
|
numStarted int
|
|
|
|
taggedMetricsHandler metrics.Handler
|
|
lastEmissionTime time.Time
|
|
}
|
|
|
|
noopSchedulerMonitor struct{}
|
|
)
|
|
|
|
func newSchedulerMonitor(
|
|
taskChannelKeyFn TaskChannelKeyFn,
|
|
namespaceRegistry namespace.Registry,
|
|
timeSource clock.TimeSource,
|
|
metricsHandler metrics.Handler,
|
|
options schedulerMonitorOptions,
|
|
) *schedulerMonitor {
|
|
return &schedulerMonitor{
|
|
taskChannelKeyFn: taskChannelKeyFn,
|
|
namespaceRegistry: namespaceRegistry,
|
|
timeSource: timeSource,
|
|
metricsHandler: metricsHandler,
|
|
options: options,
|
|
|
|
status: common.DaemonStatusInitialized,
|
|
shutdownCh: make(chan struct{}),
|
|
|
|
scheduleStats: make(map[TaskChannelKey]*scheduleStats),
|
|
}
|
|
}
|
|
|
|
func (m *schedulerMonitor) Start() {
|
|
if !atomic.CompareAndSwapInt32(&m.status, common.DaemonStatusInitialized, common.DaemonStatusStarted) {
|
|
return
|
|
}
|
|
|
|
go m.metricEmissionLoop()
|
|
}
|
|
|
|
func (m *schedulerMonitor) Stop() {
|
|
if !atomic.CompareAndSwapInt32(&m.status, common.DaemonStatusStarted, common.DaemonStatusStopped) {
|
|
return
|
|
}
|
|
|
|
close(m.shutdownCh)
|
|
}
|
|
|
|
func (m *schedulerMonitor) RecordStart(executable Executable) {
|
|
startTime := m.timeSource.Now()
|
|
taskChanKey := m.taskChannelKeyFn(executable)
|
|
|
|
m.Lock()
|
|
defer m.Unlock()
|
|
|
|
stats := m.getOrCreateScheduleStatsLocked(taskChanKey)
|
|
|
|
// The latency we want to measure is the duration between
|
|
// two task start time for one task channel.
|
|
// However, it's possible that the second task is only queued
|
|
// long after the first task is started. In that case, the
|
|
// latency becomes the duration between schedule to start time
|
|
// for the second task.
|
|
latency := min(
|
|
startTime.Sub(stats.lastStartTime),
|
|
startTime.Sub(executable.GetScheduledTime()),
|
|
)
|
|
stats.lastStartTime = startTime
|
|
stats.numStarted++
|
|
stats.totalLatency += latency
|
|
|
|
if stats.numStarted >= m.options.aggregationCount {
|
|
m.emitMetric(taskChanKey, stats)
|
|
}
|
|
}
|
|
|
|
func (m *schedulerMonitor) metricEmissionLoop() {
|
|
emissionTicker := time.NewTicker(m.options.aggregationDuration)
|
|
defer emissionTicker.Stop()
|
|
|
|
for {
|
|
select {
|
|
case <-m.shutdownCh:
|
|
return
|
|
case <-emissionTicker.C:
|
|
m.Lock()
|
|
|
|
now := m.timeSource.Now()
|
|
for taskChanKey, stats := range m.scheduleStats {
|
|
if now.Sub(stats.lastEmissionTime) > m.options.aggregationDuration {
|
|
m.emitMetric(taskChanKey, stats)
|
|
}
|
|
}
|
|
|
|
m.Unlock()
|
|
}
|
|
}
|
|
}
|
|
|
|
func (m *schedulerMonitor) getOrCreateScheduleStatsLocked(
|
|
taskChanKey TaskChannelKey,
|
|
) *scheduleStats {
|
|
if stats, ok := m.scheduleStats[taskChanKey]; ok {
|
|
return stats
|
|
}
|
|
|
|
namespaceName, _ := m.namespaceRegistry.GetNamespaceName(namespace.ID(taskChanKey.NamespaceID))
|
|
|
|
stats := &scheduleStats{
|
|
taggedMetricsHandler: m.metricsHandler.WithTags(
|
|
metrics.NamespaceTag(namespaceName.String()),
|
|
metrics.TaskPriorityTag(taskChanKey.Priority.String()),
|
|
),
|
|
lastEmissionTime: m.timeSource.Now(),
|
|
}
|
|
m.scheduleStats[taskChanKey] = stats
|
|
return stats
|
|
}
|
|
|
|
func (m *schedulerMonitor) emitMetric(
|
|
taskChanKey TaskChannelKey,
|
|
stats *scheduleStats,
|
|
) {
|
|
if stats.numStarted == 0 {
|
|
return
|
|
}
|
|
|
|
totalLatency := stats.totalLatency
|
|
if stats.numStarted != m.options.aggregationCount {
|
|
totalLatency = totalLatency / time.Duration(stats.numStarted) * time.Duration(m.options.aggregationCount)
|
|
}
|
|
|
|
metrics.QueueScheduleLatency.With(stats.taggedMetricsHandler).Record(totalLatency)
|
|
m.resetStats(stats)
|
|
}
|
|
|
|
func (m *schedulerMonitor) resetStats(
|
|
stats *scheduleStats,
|
|
) {
|
|
stats.numStarted = 0
|
|
stats.totalLatency = 0
|
|
stats.lastEmissionTime = m.timeSource.Now()
|
|
}
|
|
|
|
func (m *noopSchedulerMonitor) Start() {}
|
|
func (m *noopSchedulerMonitor) Stop() {}
|
|
func (m *noopSchedulerMonitor) RecordStart(_ Executable) {}
|