Files
geo/server/internal/tenant/app/monitoring_received_inspection.go
T

131 lines
3.5 KiB
Go

package app
import (
"context"
"time"
"github.com/jackc/pgx/v5"
)
const (
defaultMonitoringReceivedAlertThreshold = 15 * time.Minute
defaultMonitoringReceivedInspectLimit = 100
)
type monitoringStaleReceivedTask struct {
ID int64
TenantID int64
BrandID int64
QuestionID int64
AIPlatformID string
CollectorType string
BusinessDate time.Time
CallbackReceivedAt time.Time
}
type MonitoringStaleReceivedTask = monitoringStaleReceivedTask
func markMonitoringStaleReceivedTasks(ctx context.Context, tx pgx.Tx, now time.Time, threshold time.Duration, limit int) ([]monitoringStaleReceivedTask, error) {
if limit <= 0 {
limit = defaultMonitoringReceivedInspectLimit
}
rows, err := tx.Query(ctx, `
WITH candidates AS (
SELECT
id,
tenant_id,
brand_id,
question_id,
ai_platform_id,
collector_type,
business_date,
callback_received_at
FROM monitoring_collect_tasks
WHERE collector_type = $1
AND (
status = 'received'
OR (
COALESCE(execution_owner, 'legacy') = 'desktop_tasks'
AND status = 'pending'
AND callback_received_at IS NOT NULL
)
)
AND callback_received_at IS NOT NULL
AND callback_received_at < $2
AND (
request_payload_json IS NULL
OR jsonb_typeof(request_payload_json) <> 'object'
OR NOT (request_payload_json ? 'received_alerted_at')
)
ORDER BY callback_received_at ASC, id ASC
FOR UPDATE SKIP LOCKED
LIMIT $3
)
UPDATE monitoring_collect_tasks t
SET request_payload_json = (
CASE
WHEN t.request_payload_json IS NULL OR jsonb_typeof(t.request_payload_json) <> 'object'
THEN '{}'::jsonb
ELSE t.request_payload_json
END
) || jsonb_build_object(
'received_alerted_at', $4::text,
'received_alert_count', (
CASE
WHEN COALESCE(t.request_payload_json ->> 'received_alert_count', '') ~ '^[0-9]+$'
THEN (t.request_payload_json ->> 'received_alert_count')::int
ELSE 0
END
) + 1
),
updated_at = NOW()
FROM candidates c
WHERE t.id = c.id
RETURNING
c.id,
c.tenant_id,
c.brand_id,
c.question_id,
c.ai_platform_id,
c.collector_type,
c.business_date,
c.callback_received_at
`, monitoringCollectorType, now.Add(-threshold), limit, now.UTC().Format(time.RFC3339))
if err != nil {
return nil, monitoringInternalError(50041, "received_watchdog_query_failed", "failed to inspect stale received monitoring tasks", err)
}
defer rows.Close()
result := make([]monitoringStaleReceivedTask, 0)
for rows.Next() {
var item monitoringStaleReceivedTask
if scanErr := rows.Scan(
&item.ID,
&item.TenantID,
&item.BrandID,
&item.QuestionID,
&item.AIPlatformID,
&item.CollectorType,
&item.BusinessDate,
&item.CallbackReceivedAt,
); scanErr != nil {
return nil, monitoringInternalError(50041, "received_watchdog_scan_failed", "failed to parse stale received monitoring tasks", scanErr)
}
result = append(result, item)
}
if err := rows.Err(); err != nil {
return nil, monitoringInternalError(50041, "received_watchdog_scan_failed", "failed to iterate stale received monitoring tasks", err)
}
return result, nil
}
func MarkMonitoringStaleReceivedTasks(ctx context.Context, tx pgx.Tx, now time.Time, threshold time.Duration, limit int) ([]MonitoringStaleReceivedTask, error) {
items, err := markMonitoringStaleReceivedTasks(ctx, tx, now, threshold, limit)
if err != nil {
return nil, err
}
return items, nil
}