feat: sync deployed v1.0.0-rc.38-custom.42
Sync production source including routing, billing, Astra detection and public uptime. Update custom build instructions and license packaging.
This commit is contained in:
1 parent
aa6c3f50f4
commit
ceddfd3d6b
828 files changed
+122253
-13702
No files matched your search
+159
-10
@@ -21,6 +21,18 @@ const (
|
||||
StreamEndReasonPingFail StreamEndReason = "ping_fail"
|
||||
)
|
||||
|
||||
// ResponseOutcome is the protocol-level result of one response, independent of
|
||||
// how the transport ended. Adaptors mark it from the events they already parse.
|
||||
type ResponseOutcome string
|
||||
|
||||
const (
|
||||
ResponseOutcomeUnknown ResponseOutcome = ""
|
||||
ResponseOutcomeCompleted ResponseOutcome = "completed"
|
||||
ResponseOutcomeFailed ResponseOutcome = "failed"
|
||||
ResponseOutcomeIncomplete ResponseOutcome = "incomplete"
|
||||
ResponseOutcomeCancelled ResponseOutcome = "cancelled"
|
||||
)
|
||||
|
||||
const maxStreamErrorEntries = 20
|
||||
|
||||
type StreamErrorEntry struct {
|
||||
@@ -31,11 +43,32 @@ type StreamErrorEntry struct {
|
||||
type StreamStatus struct {
|
||||
EndReason StreamEndReason
|
||||
EndError error
|
||||
endOnce sync.Once
|
||||
endMu sync.Mutex
|
||||
endSet bool
|
||||
|
||||
mu sync.Mutex
|
||||
Errors []StreamErrorEntry
|
||||
ErrorCount int
|
||||
|
||||
response ResponseOutcome
|
||||
errorCode string
|
||||
errorType string
|
||||
errorStatus int
|
||||
incompleteReason string
|
||||
expectsTerminal bool
|
||||
}
|
||||
|
||||
// StreamOutcome holds classification facts only; upstream messages never
|
||||
// enter it because they may contain credentials or request content.
|
||||
type StreamOutcome struct {
|
||||
EndReason StreamEndReason
|
||||
HasErrors bool
|
||||
ExpectsTerminal bool
|
||||
Response ResponseOutcome
|
||||
ErrorCode string
|
||||
ErrorType string
|
||||
ErrorStatus int
|
||||
IncompleteReason string
|
||||
}
|
||||
|
||||
func NewStreamStatus() *StreamStatus {
|
||||
@@ -46,10 +79,30 @@ func (s *StreamStatus) SetEndReason(reason StreamEndReason, err error) {
|
||||
if s == nil {
|
||||
return
|
||||
}
|
||||
s.endOnce.Do(func() {
|
||||
s.EndReason = reason
|
||||
s.endMu.Lock()
|
||||
defer s.endMu.Unlock()
|
||||
if s.endSet {
|
||||
return
|
||||
}
|
||||
s.EndReason = reason
|
||||
s.EndError = err
|
||||
s.endSet = true
|
||||
}
|
||||
|
||||
// SetClientGone preserves the client disconnect as the diagnostic reason when
|
||||
// it races with a normal upstream terminal event. Fatal and handler-stop reasons
|
||||
// remain authoritative.
|
||||
func (s *StreamStatus) SetClientGone(err error) {
|
||||
if s == nil {
|
||||
return
|
||||
}
|
||||
s.endMu.Lock()
|
||||
defer s.endMu.Unlock()
|
||||
if !s.endSet || s.EndReason == StreamEndReasonDone || s.EndReason == StreamEndReasonEOF {
|
||||
s.EndReason = StreamEndReasonClientGone
|
||||
s.EndError = err
|
||||
})
|
||||
s.endSet = true
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StreamStatus) RecordError(msg string) {
|
||||
@@ -67,6 +120,95 @@ func (s *StreamStatus) RecordError(msg string) {
|
||||
}
|
||||
}
|
||||
|
||||
// RequireTerminal declares that the protocol always ends with an explicit
|
||||
// terminal event, so a stream that ends without one was cut short.
|
||||
func (s *StreamStatus) RequireTerminal() {
|
||||
if s == nil {
|
||||
return
|
||||
}
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
s.expectsTerminal = true
|
||||
}
|
||||
|
||||
// MarkCompleted, MarkIncomplete and MarkCancelled keep the first terminal seen;
|
||||
// MarkFailed always wins because an error after completion is still a failure.
|
||||
func (s *StreamStatus) MarkCompleted() {
|
||||
s.markTerminal(ResponseOutcomeCompleted, "")
|
||||
}
|
||||
|
||||
func (s *StreamStatus) MarkIncomplete(reason string) {
|
||||
s.markTerminal(ResponseOutcomeIncomplete, reason)
|
||||
}
|
||||
|
||||
func (s *StreamStatus) MarkCancelled() {
|
||||
s.markTerminal(ResponseOutcomeCancelled, "")
|
||||
}
|
||||
|
||||
func (s *StreamStatus) markTerminal(outcome ResponseOutcome, incompleteReason string) {
|
||||
if s == nil {
|
||||
return
|
||||
}
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
if s.response != ResponseOutcomeUnknown {
|
||||
return
|
||||
}
|
||||
s.response = outcome
|
||||
s.incompleteReason = incompleteReason
|
||||
}
|
||||
|
||||
// MarkFailed records a protocol failure. Empty details never erase details
|
||||
// recorded earlier, so a bare error envelope keeps the structured error.
|
||||
func (s *StreamStatus) MarkFailed(code, errorType string, status int) {
|
||||
if s == nil {
|
||||
return
|
||||
}
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
s.response = ResponseOutcomeFailed
|
||||
if code != "" {
|
||||
s.errorCode = code
|
||||
}
|
||||
if errorType != "" {
|
||||
s.errorType = errorType
|
||||
}
|
||||
if status != 0 {
|
||||
s.errorStatus = status
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StreamStatus) ResponseOutcome() string {
|
||||
if s == nil {
|
||||
return ""
|
||||
}
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
return string(s.response)
|
||||
}
|
||||
|
||||
func (s *StreamStatus) ResponseFailed() bool {
|
||||
return s.ResponseOutcome() == string(ResponseOutcomeFailed)
|
||||
}
|
||||
|
||||
func (s *StreamStatus) OutcomeSnapshot() StreamOutcome {
|
||||
if s == nil {
|
||||
return StreamOutcome{}
|
||||
}
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
return StreamOutcome{
|
||||
EndReason: s.EndReason,
|
||||
HasErrors: s.ErrorCount > 0,
|
||||
ExpectsTerminal: s.expectsTerminal,
|
||||
Response: s.response,
|
||||
ErrorCode: s.errorCode,
|
||||
ErrorType: s.errorType,
|
||||
ErrorStatus: s.errorStatus,
|
||||
IncompleteReason: s.incompleteReason,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StreamStatus) HasErrors() bool {
|
||||
if s == nil {
|
||||
return false
|
||||
@@ -89,9 +231,12 @@ func (s *StreamStatus) IsNormalEnd() bool {
|
||||
if s == nil {
|
||||
return true
|
||||
}
|
||||
return s.EndReason == StreamEndReasonDone ||
|
||||
s.EndReason == StreamEndReasonEOF ||
|
||||
s.EndReason == StreamEndReasonHandlerStop
|
||||
s.endMu.Lock()
|
||||
reason := s.EndReason
|
||||
s.endMu.Unlock()
|
||||
return reason == StreamEndReasonDone ||
|
||||
reason == StreamEndReasonEOF ||
|
||||
reason == StreamEndReasonHandlerStop
|
||||
}
|
||||
|
||||
func (s *StreamStatus) Summary() string {
|
||||
@@ -99,9 +244,13 @@ func (s *StreamStatus) Summary() string {
|
||||
return "StreamStatus<nil>"
|
||||
}
|
||||
b := &strings.Builder{}
|
||||
fmt.Fprintf(b, "reason=%s", s.EndReason)
|
||||
if s.EndError != nil {
|
||||
fmt.Fprintf(b, " end_error=%q", s.EndError.Error())
|
||||
s.endMu.Lock()
|
||||
reason := s.EndReason
|
||||
endError := s.EndError
|
||||
s.endMu.Unlock()
|
||||
fmt.Fprintf(b, "reason=%s", reason)
|
||||
if endError != nil {
|
||||
fmt.Fprintf(b, " end_error=%q", endError.Error())
|
||||
}
|
||||
s.mu.Lock()
|
||||
if s.ErrorCount > 0 {
|
||||
|
||||
Reference in new issue
Block a user