feat(monitoring): generate daily tasks and optimize heartbeat writes
Adds a MonitoringDailyTaskWorker that materializes and dispatches daily collect tasks from active subscription/desktop-client state, with per-run atomic metrics and a Prometheus collector. Dashboard and question-detail APIs now surface a platform_authorization_status so the UI can distinguish no-desktop-client, no-authorized-platforms, and authorized states; quota/access-state lookups resolve by request workspace instead of tenant. Hardens heartbeat: a desktop_client_primary_leases table gives per-(tenant, workspace) sticky primary selection, read-mostly lease resolution avoids a per-heartbeat transaction, and unchanged platform access reports skip snapshot upserts outside a 10-minute refresh window. Adds heartbeat primary/snapshot metrics exposed via token-protected tenant-api /api/internal/metrics endpoints plus Prometheus. Monitoring quota seed is removed from dev-seed since daily plans now derive from desktop bindings, and the projection uses the canonical six-platform catalog so platforms with zero samples still render. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3,11 +3,9 @@ package app
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
)
|
||||
|
||||
type monitoringBrandDailyAggregate struct {
|
||||
@@ -33,7 +31,7 @@ type monitoringPlatformDailyAggregate struct {
|
||||
}
|
||||
|
||||
func (s *MonitoringCallbackService) rebuildBrandDailyProjection(ctx context.Context, tx pgx.Tx, tenantID, brandID int64, businessDate time.Time) error {
|
||||
platforms, err := loadMonitoringProjectionPlatforms(ctx, s.businessPool, tenantID)
|
||||
platforms, err := loadMonitoringProjectionPlatforms(ctx, tx, tenantID, brandID, businessDate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -133,29 +131,8 @@ func (s *MonitoringCallbackService) rebuildBrandDailyProjection(ctx context.Cont
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadMonitoringProjectionPlatforms(ctx context.Context, businessPool *pgxpool.Pool, tenantID int64) ([]monitoringPlatformMetadata, error) {
|
||||
enabled := []string{"yuanbao", "kimi", "wenxin", "deepseek", "doubao", "qwen"}
|
||||
|
||||
var enabledJSON []byte
|
||||
if err := businessPool.QueryRow(ctx, `
|
||||
SELECT enabled_platforms
|
||||
FROM tenant_monitoring_quotas
|
||||
WHERE tenant_id = $1
|
||||
`, tenantID).Scan(&enabledJSON); err != nil {
|
||||
if err == pgx.ErrNoRows {
|
||||
return resolveMonitoringPlatforms(enabled), nil
|
||||
}
|
||||
return nil, monitoringInternalError(50041, "quota_lookup_failed", "failed to load monitoring quota", err)
|
||||
}
|
||||
|
||||
if len(enabledJSON) > 0 {
|
||||
var configured []string
|
||||
if jsonErr := json.Unmarshal(enabledJSON, &configured); jsonErr == nil && len(configured) > 0 {
|
||||
enabled = monitoringPlatformIDs(defaultMonitoringPlatforms)
|
||||
}
|
||||
}
|
||||
|
||||
return resolveMonitoringPlatforms(enabled), nil
|
||||
func loadMonitoringProjectionPlatforms(_ context.Context, _ pgx.Tx, _ int64, _ int64, _ time.Time) ([]monitoringPlatformMetadata, error) {
|
||||
return defaultMonitoringPlatformMetadata(), nil
|
||||
}
|
||||
|
||||
func (s *MonitoringCallbackService) loadMonitoringEnabledQuestionCount(ctx context.Context, tx pgx.Tx, tenantID, brandID int64, businessDate time.Time) (int64, error) {
|
||||
|
||||
Reference in New Issue
Block a user