Relay current process output without spool
This commit is contained in:
@@ -359,6 +359,9 @@ func (worker *Worker) registerUnlocked(ctx context.Context) error {
|
||||
}
|
||||
sink.mu.Unlock()
|
||||
}
|
||||
if sink, ok := worker.executor.logSink.(*LiveLogSink); ok {
|
||||
sink.SetSession(state.RunEndpointID, state.SessionToken)
|
||||
}
|
||||
if hook, ok := worker.executor.artifactHook.(*QueueArtifactHook); ok {
|
||||
hook.RunEndpointID = state.RunEndpointID
|
||||
hook.SessionToken = state.SessionToken
|
||||
@@ -1438,6 +1441,118 @@ type SpoolLogSink struct {
|
||||
Progress func(context.Context, string, string) (uint64, error)
|
||||
}
|
||||
|
||||
type LiveLogClient interface {
|
||||
RelayLiveLogBatch(context.Context, protocol.LogBatchIngestRequest) (protocol.LogBatchIngestResponse, error)
|
||||
}
|
||||
|
||||
// LiveLogSink is process-local and best-effort. It has no disk spool, no
|
||||
// resend backlog, and does not make lifecycle execution wait for the platform.
|
||||
type LiveLogSink struct {
|
||||
Client LiveLogClient
|
||||
RunEndpointID string
|
||||
SessionToken string
|
||||
|
||||
mu sync.Mutex
|
||||
sequences map[string]uint64
|
||||
queue chan protocol.LogBatchIngestRequest
|
||||
closed bool
|
||||
closeOnce sync.Once
|
||||
}
|
||||
|
||||
func NewLiveLogSink(client LiveLogClient) *LiveLogSink {
|
||||
sink := &LiveLogSink{Client: client, sequences: map[string]uint64{}, queue: make(chan protocol.LogBatchIngestRequest, 512)}
|
||||
go sink.dispatch()
|
||||
return sink
|
||||
}
|
||||
|
||||
func (sink *LiveLogSink) SetSession(endpointID string, sessionToken string) {
|
||||
sink.mu.Lock()
|
||||
sink.RunEndpointID = endpointID
|
||||
sink.SessionToken = sessionToken
|
||||
sink.mu.Unlock()
|
||||
}
|
||||
|
||||
func (sink *LiveLogSink) Append(ctx context.Context, assignment protocol.RunJobAssignment, stream string, line string) error {
|
||||
return sink.append(assignment, stream, line)
|
||||
}
|
||||
|
||||
func (sink *LiveLogSink) AppendWithCursor(ctx context.Context, assignment protocol.RunJobAssignment, stream string, line string, _ ProcessLogCursor) error {
|
||||
return sink.append(assignment, stream, line)
|
||||
}
|
||||
|
||||
func (sink *LiveLogSink) append(assignment protocol.RunJobAssignment, stream string, line string) error {
|
||||
if sink == nil {
|
||||
return nil
|
||||
}
|
||||
redactedLine := RedactText(line)
|
||||
redacted := line != redactedLine || strings.HasPrefix(redactedLine, "[redacted protected ")
|
||||
streamKey := declaredProcessStreamKey(assignment, stream)
|
||||
logStreamID := logStreamIDForAssignment(assignment, streamKey)
|
||||
sink.mu.Lock()
|
||||
defer sink.mu.Unlock()
|
||||
if sink.closed || sink.queue == nil {
|
||||
return nil
|
||||
}
|
||||
endpointID := sink.RunEndpointID
|
||||
if endpointID == "" {
|
||||
endpointID = assignment.RunEndpointID
|
||||
}
|
||||
if endpointID == "" || sink.SessionToken == "" || assignment.ServerInstanceID == "" {
|
||||
return nil
|
||||
}
|
||||
sink.sequences[logStreamID]++
|
||||
sequence := sink.sequences[logStreamID]
|
||||
batch := protocol.LogBatchIngestRequest{
|
||||
RunEndpointID: endpointID,
|
||||
SessionToken: sink.SessionToken,
|
||||
LogStreamID: logStreamID,
|
||||
ServerInstanceID: assignment.ServerInstanceID,
|
||||
StreamKey: streamKey,
|
||||
Source: "process",
|
||||
LogSessionID: assignment.LogSessionID,
|
||||
SessionStartedAt: assignment.SessionStartedAt,
|
||||
FirstSeq: sequence,
|
||||
LastSeq: sequence,
|
||||
Compression: "none",
|
||||
Entries: []protocol.LogEntry{{Seq: sequence, Timestamp: time.Now().UTC(), Level: "info", Line: redactedLine, Redacted: redacted}},
|
||||
}
|
||||
batch.Checksum, _ = checksumForLogEntries(batch.Entries)
|
||||
select {
|
||||
case sink.queue <- batch:
|
||||
default:
|
||||
log.Printf("RUN phase=live_log_relay status=dropped stream=%s sequence=%d reason=transient_queue_full", safeOptional(logStreamID), sequence)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sink *LiveLogSink) dispatch() {
|
||||
for batch := range sink.queue {
|
||||
if sink.Client == nil {
|
||||
continue
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
||||
_, err := sink.Client.RelayLiveLogBatch(ctx, batch)
|
||||
cancel()
|
||||
if err != nil {
|
||||
log.Printf("RUN phase=live_log_relay status=dropped stream=%s sequence=%d error=%s", safeOptional(batch.LogStreamID), batch.FirstSeq, RedactText(err.Error()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (sink *LiveLogSink) Close() {
|
||||
if sink == nil {
|
||||
return
|
||||
}
|
||||
sink.closeOnce.Do(func() {
|
||||
sink.mu.Lock()
|
||||
sink.closed = true
|
||||
if sink.queue != nil {
|
||||
close(sink.queue)
|
||||
}
|
||||
sink.mu.Unlock()
|
||||
})
|
||||
}
|
||||
|
||||
func (sink *SpoolLogSink) Append(ctx context.Context, assignment protocol.RunJobAssignment, stream string, line string) error {
|
||||
return sink.append(ctx, assignment, stream, line, nil)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user