diff --git a/api/stovepipe/proto/stovepipe.proto b/api/stovepipe/proto/stovepipe.proto index a00decc9c..f698ee65d 100644 --- a/api/stovepipe/proto/stovepipe.proto +++ b/api/stovepipe/proto/stovepipe.proto @@ -54,6 +54,92 @@ message IngestResponse { string id = 1; } +// GetRequestHistoryByRequestIDRequest selects one request history by the ID +// returned from Ingest. +message GetRequestHistoryByRequestIDRequest { + // Logical queue containing the request. + string queue = 1; + // Globally unique request identifier returned from Ingest. + string request_id = 2; + // Maximum entries to return. Zero selects the server default. + int32 page_size = 3; + // Opaque continuation token. Empty selects the first page. + string page_token = 4; +} + +// GetRequestHistoryByURIRequest selects the authoritative request history for an exact commit URI. +message GetRequestHistoryByURIRequest { + // Logical queue containing the request. + string queue = 1; + // Exact VCS-agnostic commit URI whose authoritative request is selected. + string uri = 2; + // Maximum entries to return. Zero selects the server default. + int32 page_size = 3; + // Opaque continuation token. Empty selects the first page. + string page_token = 4; +} + +// ValidationResult is the immutable validation verdict for one scope. +message ValidationResult { + // Degree measures how broken the scope is on [0.0, 1.0]. Zero is fully + // green and one is fully broken. + double degree = 1; +} + +// HistoryEntry is one retained request state or lifecycle event. +message HistoryEntry { + // Opaque stable identity of this logical occurrence within the request. + string entry_id = 1; + // Occurrence time in Unix milliseconds. + int64 timestamp_ms = 2; + // Exactly one occurrence kind is populated. + oneof occurrence { + // Durable request state reached by the request. + string request_state = 3; + // Event that occurred without changing the request state. + string event = 4; + } + // Newer request that caused a superseded state. Empty when not applicable. + string superseded_by_request_id = 5; + // Build associated with the occurrence. Empty when no build applies. + string build_id = 6; + // Stable domain reason for a terminal request outcome. Empty otherwise. + string outcome_reason = 7; + // Recorded validation verdict. Present only when the occurrence established + // an immutable validation fact. + ValidationResult result = 8; +} + +// RequestHistory contains immutable request context and one ordered page of entries. +message RequestHistory { + // Globally unique request identifier. + string request_id = 1; + // VCS-agnostic commit URI validated by the request. + string uri = 2; + // Validation scope selected for the request. + string build_strategy = 3; + // Baseline URI for incremental validation. Empty for a full build. + string base_uri = 4; + // Entries ordered by occurrence time and stable entry identity. + repeated HistoryEntry entries = 5; +} + +// GetRequestHistoryByRequestIDResponse contains one page of request history. +message GetRequestHistoryByRequestIDResponse { + // Selected request history and immutable context. + RequestHistory history = 1; + // Opaque continuation token. Empty on the final page. + string next_page_token = 2; +} + +// GetRequestHistoryByURIResponse contains one page of the authoritative request's history. +message GetRequestHistoryByURIResponse { + // Selected request history and immutable context. + RequestHistory history = 1; + // Opaque continuation token. Empty on the final page. + string next_page_token = 2; +} + // Stovepipe provides the Stovepipe API. service Stovepipe { // Ping returns a response indicating the service is alive @@ -61,4 +147,8 @@ service Stovepipe { // Ingest admits a queue's newly observed commit into the validation pipeline and returns // the minted request ID. The caller hands off asynchronously; validation happens later. rpc Ingest(IngestRequest) returns (IngestResponse) {} + // GetRequestHistoryByRequestID returns retained history for one request ID. + rpc GetRequestHistoryByRequestID(GetRequestHistoryByRequestIDRequest) returns (GetRequestHistoryByRequestIDResponse) {} + // GetRequestHistoryByURI returns retained history for an exact commit URI's authoritative request. + rpc GetRequestHistoryByURI(GetRequestHistoryByURIRequest) returns (GetRequestHistoryByURIResponse) {} } diff --git a/api/stovepipe/protopb/stovepipe.pb.go b/api/stovepipe/protopb/stovepipe.pb.go index 25c1a6821..213c21834 100644 --- a/api/stovepipe/protopb/stovepipe.pb.go +++ b/api/stovepipe/protopb/stovepipe.pb.go @@ -250,6 +250,534 @@ func (x *IngestResponse) GetId() string { return "" } +// GetRequestHistoryByRequestIDRequest selects one request history by the ID +// returned from Ingest. +type GetRequestHistoryByRequestIDRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Logical queue containing the request. + Queue string `protobuf:"bytes,1,opt,name=queue,proto3" json:"queue,omitempty"` + // Globally unique request identifier returned from Ingest. + RequestId string `protobuf:"bytes,2,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"` + // Maximum entries to return. Zero selects the server default. + PageSize int32 `protobuf:"varint,3,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` + // Opaque continuation token. Empty selects the first page. + PageToken string `protobuf:"bytes,4,opt,name=page_token,json=pageToken,proto3" json:"page_token,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetRequestHistoryByRequestIDRequest) Reset() { + *x = GetRequestHistoryByRequestIDRequest{} + mi := &file_stovepipe_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetRequestHistoryByRequestIDRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetRequestHistoryByRequestIDRequest) ProtoMessage() {} + +func (x *GetRequestHistoryByRequestIDRequest) ProtoReflect() protoreflect.Message { + mi := &file_stovepipe_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetRequestHistoryByRequestIDRequest.ProtoReflect.Descriptor instead. +func (*GetRequestHistoryByRequestIDRequest) Descriptor() ([]byte, []int) { + return file_stovepipe_proto_rawDescGZIP(), []int{4} +} + +func (x *GetRequestHistoryByRequestIDRequest) GetQueue() string { + if x != nil { + return x.Queue + } + return "" +} + +func (x *GetRequestHistoryByRequestIDRequest) GetRequestId() string { + if x != nil { + return x.RequestId + } + return "" +} + +func (x *GetRequestHistoryByRequestIDRequest) GetPageSize() int32 { + if x != nil { + return x.PageSize + } + return 0 +} + +func (x *GetRequestHistoryByRequestIDRequest) GetPageToken() string { + if x != nil { + return x.PageToken + } + return "" +} + +// GetRequestHistoryByURIRequest selects the authoritative request history for an exact commit URI. +type GetRequestHistoryByURIRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Logical queue containing the request. + Queue string `protobuf:"bytes,1,opt,name=queue,proto3" json:"queue,omitempty"` + // Exact VCS-agnostic commit URI whose authoritative request is selected. + Uri string `protobuf:"bytes,2,opt,name=uri,proto3" json:"uri,omitempty"` + // Maximum entries to return. Zero selects the server default. + PageSize int32 `protobuf:"varint,3,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` + // Opaque continuation token. Empty selects the first page. + PageToken string `protobuf:"bytes,4,opt,name=page_token,json=pageToken,proto3" json:"page_token,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetRequestHistoryByURIRequest) Reset() { + *x = GetRequestHistoryByURIRequest{} + mi := &file_stovepipe_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetRequestHistoryByURIRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetRequestHistoryByURIRequest) ProtoMessage() {} + +func (x *GetRequestHistoryByURIRequest) ProtoReflect() protoreflect.Message { + mi := &file_stovepipe_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetRequestHistoryByURIRequest.ProtoReflect.Descriptor instead. +func (*GetRequestHistoryByURIRequest) Descriptor() ([]byte, []int) { + return file_stovepipe_proto_rawDescGZIP(), []int{5} +} + +func (x *GetRequestHistoryByURIRequest) GetQueue() string { + if x != nil { + return x.Queue + } + return "" +} + +func (x *GetRequestHistoryByURIRequest) GetUri() string { + if x != nil { + return x.Uri + } + return "" +} + +func (x *GetRequestHistoryByURIRequest) GetPageSize() int32 { + if x != nil { + return x.PageSize + } + return 0 +} + +func (x *GetRequestHistoryByURIRequest) GetPageToken() string { + if x != nil { + return x.PageToken + } + return "" +} + +// ValidationResult is the immutable validation verdict for one scope. +type ValidationResult struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Degree measures how broken the scope is on [0.0, 1.0]. Zero is fully + // green and one is fully broken. + Degree float64 `protobuf:"fixed64,1,opt,name=degree,proto3" json:"degree,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ValidationResult) Reset() { + *x = ValidationResult{} + mi := &file_stovepipe_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ValidationResult) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ValidationResult) ProtoMessage() {} + +func (x *ValidationResult) ProtoReflect() protoreflect.Message { + mi := &file_stovepipe_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ValidationResult.ProtoReflect.Descriptor instead. +func (*ValidationResult) Descriptor() ([]byte, []int) { + return file_stovepipe_proto_rawDescGZIP(), []int{6} +} + +func (x *ValidationResult) GetDegree() float64 { + if x != nil { + return x.Degree + } + return 0 +} + +// HistoryEntry is one retained request state or lifecycle event. +type HistoryEntry struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Opaque stable identity of this logical occurrence within the request. + EntryId string `protobuf:"bytes,1,opt,name=entry_id,json=entryId,proto3" json:"entry_id,omitempty"` + // Occurrence time in Unix milliseconds. + TimestampMs int64 `protobuf:"varint,2,opt,name=timestamp_ms,json=timestampMs,proto3" json:"timestamp_ms,omitempty"` + // Exactly one occurrence kind is populated. + // + // Types that are valid to be assigned to Occurrence: + // + // *HistoryEntry_RequestState + // *HistoryEntry_Event + Occurrence isHistoryEntry_Occurrence `protobuf_oneof:"occurrence"` + // Newer request that caused a superseded state. Empty when not applicable. + SupersededByRequestId string `protobuf:"bytes,5,opt,name=superseded_by_request_id,json=supersededByRequestId,proto3" json:"superseded_by_request_id,omitempty"` + // Build associated with the occurrence. Empty when no build applies. + BuildId string `protobuf:"bytes,6,opt,name=build_id,json=buildId,proto3" json:"build_id,omitempty"` + // Stable domain reason for a terminal request outcome. Empty otherwise. + OutcomeReason string `protobuf:"bytes,7,opt,name=outcome_reason,json=outcomeReason,proto3" json:"outcome_reason,omitempty"` + // Recorded validation verdict. Present only when the occurrence established + // an immutable validation fact. + Result *ValidationResult `protobuf:"bytes,8,opt,name=result,proto3" json:"result,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *HistoryEntry) Reset() { + *x = HistoryEntry{} + mi := &file_stovepipe_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *HistoryEntry) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HistoryEntry) ProtoMessage() {} + +func (x *HistoryEntry) ProtoReflect() protoreflect.Message { + mi := &file_stovepipe_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HistoryEntry.ProtoReflect.Descriptor instead. +func (*HistoryEntry) Descriptor() ([]byte, []int) { + return file_stovepipe_proto_rawDescGZIP(), []int{7} +} + +func (x *HistoryEntry) GetEntryId() string { + if x != nil { + return x.EntryId + } + return "" +} + +func (x *HistoryEntry) GetTimestampMs() int64 { + if x != nil { + return x.TimestampMs + } + return 0 +} + +func (x *HistoryEntry) GetOccurrence() isHistoryEntry_Occurrence { + if x != nil { + return x.Occurrence + } + return nil +} + +func (x *HistoryEntry) GetRequestState() string { + if x != nil { + if x, ok := x.Occurrence.(*HistoryEntry_RequestState); ok { + return x.RequestState + } + } + return "" +} + +func (x *HistoryEntry) GetEvent() string { + if x != nil { + if x, ok := x.Occurrence.(*HistoryEntry_Event); ok { + return x.Event + } + } + return "" +} + +func (x *HistoryEntry) GetSupersededByRequestId() string { + if x != nil { + return x.SupersededByRequestId + } + return "" +} + +func (x *HistoryEntry) GetBuildId() string { + if x != nil { + return x.BuildId + } + return "" +} + +func (x *HistoryEntry) GetOutcomeReason() string { + if x != nil { + return x.OutcomeReason + } + return "" +} + +func (x *HistoryEntry) GetResult() *ValidationResult { + if x != nil { + return x.Result + } + return nil +} + +type isHistoryEntry_Occurrence interface { + isHistoryEntry_Occurrence() +} + +type HistoryEntry_RequestState struct { + // Durable request state reached by the request. + RequestState string `protobuf:"bytes,3,opt,name=request_state,json=requestState,proto3,oneof"` +} + +type HistoryEntry_Event struct { + // Event that occurred without changing the request state. + Event string `protobuf:"bytes,4,opt,name=event,proto3,oneof"` +} + +func (*HistoryEntry_RequestState) isHistoryEntry_Occurrence() {} + +func (*HistoryEntry_Event) isHistoryEntry_Occurrence() {} + +// RequestHistory contains immutable request context and one ordered page of entries. +type RequestHistory struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Globally unique request identifier. + RequestId string `protobuf:"bytes,1,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"` + // VCS-agnostic commit URI validated by the request. + Uri string `protobuf:"bytes,2,opt,name=uri,proto3" json:"uri,omitempty"` + // Validation scope selected for the request. + BuildStrategy string `protobuf:"bytes,3,opt,name=build_strategy,json=buildStrategy,proto3" json:"build_strategy,omitempty"` + // Baseline URI for incremental validation. Empty for a full build. + BaseUri string `protobuf:"bytes,4,opt,name=base_uri,json=baseUri,proto3" json:"base_uri,omitempty"` + // Entries ordered by occurrence time and stable entry identity. + Entries []*HistoryEntry `protobuf:"bytes,5,rep,name=entries,proto3" json:"entries,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *RequestHistory) Reset() { + *x = RequestHistory{} + mi := &file_stovepipe_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RequestHistory) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RequestHistory) ProtoMessage() {} + +func (x *RequestHistory) ProtoReflect() protoreflect.Message { + mi := &file_stovepipe_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RequestHistory.ProtoReflect.Descriptor instead. +func (*RequestHistory) Descriptor() ([]byte, []int) { + return file_stovepipe_proto_rawDescGZIP(), []int{8} +} + +func (x *RequestHistory) GetRequestId() string { + if x != nil { + return x.RequestId + } + return "" +} + +func (x *RequestHistory) GetUri() string { + if x != nil { + return x.Uri + } + return "" +} + +func (x *RequestHistory) GetBuildStrategy() string { + if x != nil { + return x.BuildStrategy + } + return "" +} + +func (x *RequestHistory) GetBaseUri() string { + if x != nil { + return x.BaseUri + } + return "" +} + +func (x *RequestHistory) GetEntries() []*HistoryEntry { + if x != nil { + return x.Entries + } + return nil +} + +// GetRequestHistoryByRequestIDResponse contains one page of request history. +type GetRequestHistoryByRequestIDResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Selected request history and immutable context. + History *RequestHistory `protobuf:"bytes,1,opt,name=history,proto3" json:"history,omitempty"` + // Opaque continuation token. Empty on the final page. + NextPageToken string `protobuf:"bytes,2,opt,name=next_page_token,json=nextPageToken,proto3" json:"next_page_token,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetRequestHistoryByRequestIDResponse) Reset() { + *x = GetRequestHistoryByRequestIDResponse{} + mi := &file_stovepipe_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetRequestHistoryByRequestIDResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetRequestHistoryByRequestIDResponse) ProtoMessage() {} + +func (x *GetRequestHistoryByRequestIDResponse) ProtoReflect() protoreflect.Message { + mi := &file_stovepipe_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetRequestHistoryByRequestIDResponse.ProtoReflect.Descriptor instead. +func (*GetRequestHistoryByRequestIDResponse) Descriptor() ([]byte, []int) { + return file_stovepipe_proto_rawDescGZIP(), []int{9} +} + +func (x *GetRequestHistoryByRequestIDResponse) GetHistory() *RequestHistory { + if x != nil { + return x.History + } + return nil +} + +func (x *GetRequestHistoryByRequestIDResponse) GetNextPageToken() string { + if x != nil { + return x.NextPageToken + } + return "" +} + +// GetRequestHistoryByURIResponse contains one page of the authoritative request's history. +type GetRequestHistoryByURIResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Selected request history and immutable context. + History *RequestHistory `protobuf:"bytes,1,opt,name=history,proto3" json:"history,omitempty"` + // Opaque continuation token. Empty on the final page. + NextPageToken string `protobuf:"bytes,2,opt,name=next_page_token,json=nextPageToken,proto3" json:"next_page_token,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetRequestHistoryByURIResponse) Reset() { + *x = GetRequestHistoryByURIResponse{} + mi := &file_stovepipe_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetRequestHistoryByURIResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetRequestHistoryByURIResponse) ProtoMessage() {} + +func (x *GetRequestHistoryByURIResponse) ProtoReflect() protoreflect.Message { + mi := &file_stovepipe_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetRequestHistoryByURIResponse.ProtoReflect.Descriptor instead. +func (*GetRequestHistoryByURIResponse) Descriptor() ([]byte, []int) { + return file_stovepipe_proto_rawDescGZIP(), []int{10} +} + +func (x *GetRequestHistoryByURIResponse) GetHistory() *RequestHistory { + if x != nil { + return x.History + } + return nil +} + +func (x *GetRequestHistoryByURIResponse) GetNextPageToken() string { + if x != nil { + return x.NextPageToken + } + return "" +} + var File_stovepipe_proto protoreflect.FileDescriptor const file_stovepipe_proto_rawDesc = "" + @@ -265,10 +793,51 @@ const file_stovepipe_proto_rawDesc = "" + "\rIngestRequest\x12\x14\n" + "\x05queue\x18\x01 \x01(\tR\x05queue\" \n" + "\x0eIngestResponse\x12\x0e\n" + - "\x02id\x18\x01 \x01(\tR\x02id2\xcb\x01\n" + + "\x02id\x18\x01 \x01(\tR\x02id\"\x96\x01\n" + + "#GetRequestHistoryByRequestIDRequest\x12\x14\n" + + "\x05queue\x18\x01 \x01(\tR\x05queue\x12\x1d\n" + + "\n" + + "request_id\x18\x02 \x01(\tR\trequestId\x12\x1b\n" + + "\tpage_size\x18\x03 \x01(\x05R\bpageSize\x12\x1d\n" + + "\n" + + "page_token\x18\x04 \x01(\tR\tpageToken\"\x83\x01\n" + + "\x1dGetRequestHistoryByURIRequest\x12\x14\n" + + "\x05queue\x18\x01 \x01(\tR\x05queue\x12\x10\n" + + "\x03uri\x18\x02 \x01(\tR\x03uri\x12\x1b\n" + + "\tpage_size\x18\x03 \x01(\x05R\bpageSize\x12\x1d\n" + + "\n" + + "page_token\x18\x04 \x01(\tR\tpageToken\"*\n" + + "\x10ValidationResult\x12\x16\n" + + "\x06degree\x18\x01 \x01(\x01R\x06degree\"\xda\x02\n" + + "\fHistoryEntry\x12\x19\n" + + "\bentry_id\x18\x01 \x01(\tR\aentryId\x12!\n" + + "\ftimestamp_ms\x18\x02 \x01(\x03R\vtimestampMs\x12%\n" + + "\rrequest_state\x18\x03 \x01(\tH\x00R\frequestState\x12\x16\n" + + "\x05event\x18\x04 \x01(\tH\x00R\x05event\x127\n" + + "\x18superseded_by_request_id\x18\x05 \x01(\tR\x15supersededByRequestId\x12\x19\n" + + "\bbuild_id\x18\x06 \x01(\tR\abuildId\x12%\n" + + "\x0eoutcome_reason\x18\a \x01(\tR\routcomeReason\x12D\n" + + "\x06result\x18\b \x01(\v2,.uber.submitqueue.stovepipe.ValidationResultR\x06resultB\f\n" + + "\n" + + "occurrence\"\xc7\x01\n" + + "\x0eRequestHistory\x12\x1d\n" + + "\n" + + "request_id\x18\x01 \x01(\tR\trequestId\x12\x10\n" + + "\x03uri\x18\x02 \x01(\tR\x03uri\x12%\n" + + "\x0ebuild_strategy\x18\x03 \x01(\tR\rbuildStrategy\x12\x19\n" + + "\bbase_uri\x18\x04 \x01(\tR\abaseUri\x12B\n" + + "\aentries\x18\x05 \x03(\v2(.uber.submitqueue.stovepipe.HistoryEntryR\aentries\"\x94\x01\n" + + "$GetRequestHistoryByRequestIDResponse\x12D\n" + + "\ahistory\x18\x01 \x01(\v2*.uber.submitqueue.stovepipe.RequestHistoryR\ahistory\x12&\n" + + "\x0fnext_page_token\x18\x02 \x01(\tR\rnextPageToken\"\x8e\x01\n" + + "\x1eGetRequestHistoryByURIResponse\x12D\n" + + "\ahistory\x18\x01 \x01(\v2*.uber.submitqueue.stovepipe.RequestHistoryR\ahistory\x12&\n" + + "\x0fnext_page_token\x18\x02 \x01(\tR\rnextPageToken2\x85\x04\n" + "\tStovepipe\x12[\n" + "\x04Ping\x12'.uber.submitqueue.stovepipe.PingRequest\x1a(.uber.submitqueue.stovepipe.PingResponse\"\x00\x12a\n" + - "\x06Ingest\x12).uber.submitqueue.stovepipe.IngestRequest\x1a*.uber.submitqueue.stovepipe.IngestResponse\"\x00Be\n" + + "\x06Ingest\x12).uber.submitqueue.stovepipe.IngestRequest\x1a*.uber.submitqueue.stovepipe.IngestResponse\"\x00\x12\xa3\x01\n" + + "\x1cGetRequestHistoryByRequestID\x12?.uber.submitqueue.stovepipe.GetRequestHistoryByRequestIDRequest\x1a@.uber.submitqueue.stovepipe.GetRequestHistoryByRequestIDResponse\"\x00\x12\x91\x01\n" + + "\x16GetRequestHistoryByURI\x129.uber.submitqueue.stovepipe.GetRequestHistoryByURIRequest\x1a:.uber.submitqueue.stovepipe.GetRequestHistoryByURIResponse\"\x00Be\n" + "\x1ecom.uber.submitqueue.stovepipeB\x0eStovepipeProtoP\x01Z1github.com/uber/submitqueue/api/stovepipe/protopbb\x06proto3" var ( @@ -283,23 +852,38 @@ func file_stovepipe_proto_rawDescGZIP() []byte { return file_stovepipe_proto_rawDescData } -var file_stovepipe_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_stovepipe_proto_msgTypes = make([]protoimpl.MessageInfo, 11) var file_stovepipe_proto_goTypes = []any{ - (*PingRequest)(nil), // 0: uber.submitqueue.stovepipe.PingRequest - (*PingResponse)(nil), // 1: uber.submitqueue.stovepipe.PingResponse - (*IngestRequest)(nil), // 2: uber.submitqueue.stovepipe.IngestRequest - (*IngestResponse)(nil), // 3: uber.submitqueue.stovepipe.IngestResponse + (*PingRequest)(nil), // 0: uber.submitqueue.stovepipe.PingRequest + (*PingResponse)(nil), // 1: uber.submitqueue.stovepipe.PingResponse + (*IngestRequest)(nil), // 2: uber.submitqueue.stovepipe.IngestRequest + (*IngestResponse)(nil), // 3: uber.submitqueue.stovepipe.IngestResponse + (*GetRequestHistoryByRequestIDRequest)(nil), // 4: uber.submitqueue.stovepipe.GetRequestHistoryByRequestIDRequest + (*GetRequestHistoryByURIRequest)(nil), // 5: uber.submitqueue.stovepipe.GetRequestHistoryByURIRequest + (*ValidationResult)(nil), // 6: uber.submitqueue.stovepipe.ValidationResult + (*HistoryEntry)(nil), // 7: uber.submitqueue.stovepipe.HistoryEntry + (*RequestHistory)(nil), // 8: uber.submitqueue.stovepipe.RequestHistory + (*GetRequestHistoryByRequestIDResponse)(nil), // 9: uber.submitqueue.stovepipe.GetRequestHistoryByRequestIDResponse + (*GetRequestHistoryByURIResponse)(nil), // 10: uber.submitqueue.stovepipe.GetRequestHistoryByURIResponse } var file_stovepipe_proto_depIdxs = []int32{ - 0, // 0: uber.submitqueue.stovepipe.Stovepipe.Ping:input_type -> uber.submitqueue.stovepipe.PingRequest - 2, // 1: uber.submitqueue.stovepipe.Stovepipe.Ingest:input_type -> uber.submitqueue.stovepipe.IngestRequest - 1, // 2: uber.submitqueue.stovepipe.Stovepipe.Ping:output_type -> uber.submitqueue.stovepipe.PingResponse - 3, // 3: uber.submitqueue.stovepipe.Stovepipe.Ingest:output_type -> uber.submitqueue.stovepipe.IngestResponse - 2, // [2:4] is the sub-list for method output_type - 0, // [0:2] is the sub-list for method input_type - 0, // [0:0] is the sub-list for extension type_name - 0, // [0:0] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name + 6, // 0: uber.submitqueue.stovepipe.HistoryEntry.result:type_name -> uber.submitqueue.stovepipe.ValidationResult + 7, // 1: uber.submitqueue.stovepipe.RequestHistory.entries:type_name -> uber.submitqueue.stovepipe.HistoryEntry + 8, // 2: uber.submitqueue.stovepipe.GetRequestHistoryByRequestIDResponse.history:type_name -> uber.submitqueue.stovepipe.RequestHistory + 8, // 3: uber.submitqueue.stovepipe.GetRequestHistoryByURIResponse.history:type_name -> uber.submitqueue.stovepipe.RequestHistory + 0, // 4: uber.submitqueue.stovepipe.Stovepipe.Ping:input_type -> uber.submitqueue.stovepipe.PingRequest + 2, // 5: uber.submitqueue.stovepipe.Stovepipe.Ingest:input_type -> uber.submitqueue.stovepipe.IngestRequest + 4, // 6: uber.submitqueue.stovepipe.Stovepipe.GetRequestHistoryByRequestID:input_type -> uber.submitqueue.stovepipe.GetRequestHistoryByRequestIDRequest + 5, // 7: uber.submitqueue.stovepipe.Stovepipe.GetRequestHistoryByURI:input_type -> uber.submitqueue.stovepipe.GetRequestHistoryByURIRequest + 1, // 8: uber.submitqueue.stovepipe.Stovepipe.Ping:output_type -> uber.submitqueue.stovepipe.PingResponse + 3, // 9: uber.submitqueue.stovepipe.Stovepipe.Ingest:output_type -> uber.submitqueue.stovepipe.IngestResponse + 9, // 10: uber.submitqueue.stovepipe.Stovepipe.GetRequestHistoryByRequestID:output_type -> uber.submitqueue.stovepipe.GetRequestHistoryByRequestIDResponse + 10, // 11: uber.submitqueue.stovepipe.Stovepipe.GetRequestHistoryByURI:output_type -> uber.submitqueue.stovepipe.GetRequestHistoryByURIResponse + 8, // [8:12] is the sub-list for method output_type + 4, // [4:8] is the sub-list for method input_type + 4, // [4:4] is the sub-list for extension type_name + 4, // [4:4] is the sub-list for extension extendee + 0, // [0:4] is the sub-list for field type_name } func init() { file_stovepipe_proto_init() } @@ -307,13 +891,17 @@ func file_stovepipe_proto_init() { if File_stovepipe_proto != nil { return } + file_stovepipe_proto_msgTypes[7].OneofWrappers = []any{ + (*HistoryEntry_RequestState)(nil), + (*HistoryEntry_Event)(nil), + } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_stovepipe_proto_rawDesc), len(file_stovepipe_proto_rawDesc)), NumEnums: 0, - NumMessages: 4, + NumMessages: 11, NumExtensions: 0, NumServices: 1, }, diff --git a/api/stovepipe/protopb/stovepipe.pb.yarpc.go b/api/stovepipe/protopb/stovepipe.pb.yarpc.go index ad6fe9eb5..b0dd30df4 100644 --- a/api/stovepipe/protopb/stovepipe.pb.yarpc.go +++ b/api/stovepipe/protopb/stovepipe.pb.yarpc.go @@ -23,6 +23,8 @@ var _ = ioutil.NopCloser type StovepipeYARPCClient interface { Ping(context.Context, *PingRequest, ...yarpc.CallOption) (*PingResponse, error) Ingest(context.Context, *IngestRequest, ...yarpc.CallOption) (*IngestResponse, error) + GetRequestHistoryByRequestID(context.Context, *GetRequestHistoryByRequestIDRequest, ...yarpc.CallOption) (*GetRequestHistoryByRequestIDResponse, error) + GetRequestHistoryByURI(context.Context, *GetRequestHistoryByURIRequest, ...yarpc.CallOption) (*GetRequestHistoryByURIResponse, error) } func newStovepipeYARPCClient(clientConfig transport.ClientConfig, anyResolver v2.AnyResolver, options ...v2.ClientOption) StovepipeYARPCClient { @@ -45,6 +47,8 @@ func NewStovepipeYARPCClient(clientConfig transport.ClientConfig, options ...v2. type StovepipeYARPCServer interface { Ping(context.Context, *PingRequest) (*PingResponse, error) Ingest(context.Context, *IngestRequest) (*IngestResponse, error) + GetRequestHistoryByRequestID(context.Context, *GetRequestHistoryByRequestIDRequest) (*GetRequestHistoryByRequestIDResponse, error) + GetRequestHistoryByURI(context.Context, *GetRequestHistoryByURIRequest) (*GetRequestHistoryByURIResponse, error) } type buildStovepipeYARPCProceduresParams struct { @@ -78,6 +82,26 @@ func buildStovepipeYARPCProcedures(params buildStovepipeYARPCProceduresParams) [ }, ), }, + { + MethodName: "GetRequestHistoryByRequestID", + Handler: v2.NewUnaryHandler( + v2.UnaryHandlerParams{ + Handle: handler.GetRequestHistoryByRequestID, + NewRequest: newStovepipeServiceGetRequestHistoryByRequestIDYARPCRequest, + AnyResolver: params.AnyResolver, + }, + ), + }, + { + MethodName: "GetRequestHistoryByURI", + Handler: v2.NewUnaryHandler( + v2.UnaryHandlerParams{ + Handle: handler.GetRequestHistoryByURI, + NewRequest: newStovepipeServiceGetRequestHistoryByURIYARPCRequest, + AnyResolver: params.AnyResolver, + }, + ), + }, }, OnewayHandlerParams: []v2.BuildProceduresOnewayHandlerParams{}, StreamHandlerParams: []v2.BuildProceduresStreamHandlerParams{}, @@ -214,6 +238,30 @@ func (c *_StovepipeYARPCCaller) Ingest(ctx context.Context, request *IngestReque return response, err } +func (c *_StovepipeYARPCCaller) GetRequestHistoryByRequestID(ctx context.Context, request *GetRequestHistoryByRequestIDRequest, options ...yarpc.CallOption) (*GetRequestHistoryByRequestIDResponse, error) { + responseMessage, err := c.streamClient.Call(ctx, "GetRequestHistoryByRequestID", request, newStovepipeServiceGetRequestHistoryByRequestIDYARPCResponse, options...) + if responseMessage == nil { + return nil, err + } + response, ok := responseMessage.(*GetRequestHistoryByRequestIDResponse) + if !ok { + return nil, v2.CastError(emptyStovepipeServiceGetRequestHistoryByRequestIDYARPCResponse, responseMessage) + } + return response, err +} + +func (c *_StovepipeYARPCCaller) GetRequestHistoryByURI(ctx context.Context, request *GetRequestHistoryByURIRequest, options ...yarpc.CallOption) (*GetRequestHistoryByURIResponse, error) { + responseMessage, err := c.streamClient.Call(ctx, "GetRequestHistoryByURI", request, newStovepipeServiceGetRequestHistoryByURIYARPCResponse, options...) + if responseMessage == nil { + return nil, err + } + response, ok := responseMessage.(*GetRequestHistoryByURIResponse) + if !ok { + return nil, v2.CastError(emptyStovepipeServiceGetRequestHistoryByURIYARPCResponse, responseMessage) + } + return response, err +} + type _StovepipeYARPCHandler struct { server StovepipeYARPCServer } @@ -250,6 +298,38 @@ func (h *_StovepipeYARPCHandler) Ingest(ctx context.Context, requestMessage prot return response, err } +func (h *_StovepipeYARPCHandler) GetRequestHistoryByRequestID(ctx context.Context, requestMessage proto.Message) (proto.Message, error) { + var request *GetRequestHistoryByRequestIDRequest + var ok bool + if requestMessage != nil { + request, ok = requestMessage.(*GetRequestHistoryByRequestIDRequest) + if !ok { + return nil, v2.CastError(emptyStovepipeServiceGetRequestHistoryByRequestIDYARPCRequest, requestMessage) + } + } + response, err := h.server.GetRequestHistoryByRequestID(ctx, request) + if response == nil { + return nil, err + } + return response, err +} + +func (h *_StovepipeYARPCHandler) GetRequestHistoryByURI(ctx context.Context, requestMessage proto.Message) (proto.Message, error) { + var request *GetRequestHistoryByURIRequest + var ok bool + if requestMessage != nil { + request, ok = requestMessage.(*GetRequestHistoryByURIRequest) + if !ok { + return nil, v2.CastError(emptyStovepipeServiceGetRequestHistoryByURIYARPCRequest, requestMessage) + } + } + response, err := h.server.GetRequestHistoryByURI(ctx, request) + if response == nil { + return nil, err + } + return response, err +} + func newStovepipeServicePingYARPCRequest() proto.Message { return &PingRequest{} } @@ -266,36 +346,84 @@ func newStovepipeServiceIngestYARPCResponse() proto.Message { return &IngestResponse{} } +func newStovepipeServiceGetRequestHistoryByRequestIDYARPCRequest() proto.Message { + return &GetRequestHistoryByRequestIDRequest{} +} + +func newStovepipeServiceGetRequestHistoryByRequestIDYARPCResponse() proto.Message { + return &GetRequestHistoryByRequestIDResponse{} +} + +func newStovepipeServiceGetRequestHistoryByURIYARPCRequest() proto.Message { + return &GetRequestHistoryByURIRequest{} +} + +func newStovepipeServiceGetRequestHistoryByURIYARPCResponse() proto.Message { + return &GetRequestHistoryByURIResponse{} +} + var ( - emptyStovepipeServicePingYARPCRequest = &PingRequest{} - emptyStovepipeServicePingYARPCResponse = &PingResponse{} - emptyStovepipeServiceIngestYARPCRequest = &IngestRequest{} - emptyStovepipeServiceIngestYARPCResponse = &IngestResponse{} + emptyStovepipeServicePingYARPCRequest = &PingRequest{} + emptyStovepipeServicePingYARPCResponse = &PingResponse{} + emptyStovepipeServiceIngestYARPCRequest = &IngestRequest{} + emptyStovepipeServiceIngestYARPCResponse = &IngestResponse{} + emptyStovepipeServiceGetRequestHistoryByRequestIDYARPCRequest = &GetRequestHistoryByRequestIDRequest{} + emptyStovepipeServiceGetRequestHistoryByRequestIDYARPCResponse = &GetRequestHistoryByRequestIDResponse{} + emptyStovepipeServiceGetRequestHistoryByURIYARPCRequest = &GetRequestHistoryByURIRequest{} + emptyStovepipeServiceGetRequestHistoryByURIYARPCResponse = &GetRequestHistoryByURIResponse{} ) var yarpcFileDescriptorClosurefabdb6b3c0b09022 = [][]byte{ // stovepipe.proto []byte{ - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0x4f, 0x4e, 0xf3, 0x30, - 0x10, 0xc5, 0x3f, 0xb7, 0xfd, 0x0a, 0x9d, 0x96, 0x22, 0x59, 0x2c, 0xa2, 0x08, 0xa1, 0x12, 0x09, - 0xb5, 0xb0, 0x70, 0x04, 0xdc, 0xa0, 0x3b, 0x36, 0xa8, 0x0a, 0x3b, 0x58, 0x20, 0x27, 0x1d, 0xa5, - 0x5e, 0x38, 0x76, 0x63, 0xbb, 0x37, 0xe0, 0x74, 0x5c, 0x0a, 0xc5, 0xf9, 0x43, 0x59, 0xb4, 0xb0, - 0xf3, 0x8c, 0xdf, 0x4f, 0xf3, 0xde, 0x68, 0xe0, 0xdc, 0x58, 0xb5, 0x43, 0x2d, 0x34, 0x32, 0x5d, - 0x2a, 0xab, 0x68, 0xe8, 0x52, 0x2c, 0x99, 0x71, 0xa9, 0x14, 0x76, 0xeb, 0xd0, 0x21, 0xeb, 0x14, - 0xd1, 0x1c, 0xc6, 0x2b, 0x51, 0xe4, 0x09, 0x6e, 0x1d, 0x1a, 0x4b, 0x03, 0x38, 0x91, 0x68, 0x0c, - 0xcf, 0x31, 0x20, 0x33, 0xb2, 0x18, 0x25, 0x6d, 0x19, 0x7d, 0x10, 0x98, 0xd4, 0x4a, 0xa3, 0x55, - 0x61, 0xf0, 0xb0, 0x94, 0x5e, 0xc3, 0xc4, 0x60, 0xb9, 0x13, 0x19, 0xbe, 0x17, 0x5c, 0x62, 0xd0, - 0xf3, 0xdf, 0xe3, 0xa6, 0xf7, 0xcc, 0x25, 0xd2, 0x4b, 0x18, 0x59, 0x21, 0xd1, 0x58, 0x2e, 0x75, - 0xd0, 0x9f, 0x91, 0x45, 0x3f, 0xf9, 0x6e, 0xd0, 0x10, 0x4e, 0x37, 0xca, 0x58, 0x0f, 0x0f, 0x3c, - 0xdc, 0xd5, 0xd1, 0x0d, 0x9c, 0x3d, 0x15, 0x39, 0x1a, 0xdb, 0x5a, 0xbe, 0x80, 0xff, 0x3e, 0x54, - 0xe3, 0xa2, 0x2e, 0xa2, 0x19, 0x4c, 0x5b, 0x59, 0xe3, 0x77, 0x0a, 0x3d, 0xb1, 0x6e, 0x44, 0x3d, - 0xb1, 0x7e, 0xf8, 0x24, 0x30, 0x7a, 0x69, 0xf7, 0x40, 0xdf, 0x60, 0x50, 0xa5, 0xa3, 0x73, 0x76, - 0x78, 0x59, 0x6c, 0x6f, 0x53, 0xe1, 0xe2, 0x77, 0x61, 0x3d, 0x38, 0xfa, 0x47, 0x39, 0x0c, 0x6b, - 0x33, 0xf4, 0xf6, 0x18, 0xf5, 0x23, 0x57, 0x78, 0xf7, 0x17, 0x69, 0x3b, 0x62, 0x89, 0x70, 0x95, - 0x29, 0x79, 0x04, 0x59, 0x4e, 0xbb, 0xb0, 0xab, 0xea, 0x2a, 0x56, 0xe4, 0xf5, 0x3e, 0x17, 0x76, - 0xe3, 0x52, 0x96, 0x29, 0x19, 0x57, 0x60, 0xbc, 0x07, 0xc6, 0x5c, 0x8b, 0xb8, 0x83, 0x63, 0x7f, - 0x48, 0x3a, 0x4d, 0x87, 0xfe, 0xf1, 0xf8, 0x15, 0x00, 0x00, 0xff, 0xff, 0xc1, 0x6e, 0x43, 0xbc, - 0x64, 0x02, 0x00, 0x00, + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x56, 0xcd, 0x6e, 0x13, 0x49, + 0x10, 0xce, 0xf8, 0xdf, 0xe5, 0x9f, 0x44, 0xad, 0xdd, 0x68, 0xd6, 0x9b, 0x44, 0xde, 0xd9, 0xf5, + 0xc6, 0x1b, 0xad, 0x6c, 0x61, 0x0e, 0x08, 0x2e, 0x20, 0x2b, 0x88, 0xf8, 0x00, 0xb2, 0xc6, 0x84, + 0x03, 0x1c, 0x46, 0x63, 0x4f, 0xc9, 0x69, 0x91, 0xf9, 0x49, 0x77, 0x4f, 0x84, 0x73, 0x45, 0xb9, + 0x22, 0x21, 0x21, 0x5e, 0x80, 0x87, 0xe1, 0x1d, 0x78, 0x1a, 0x34, 0x3d, 0x3d, 0x63, 0x27, 0x24, + 0x43, 0x08, 0x07, 0x6e, 0x53, 0x5f, 0x7f, 0x5f, 0xf5, 0x57, 0xd5, 0xd5, 0x6d, 0xc3, 0x3a, 0x17, + 0xfe, 0x29, 0x06, 0x34, 0xc0, 0x5e, 0xc0, 0x7c, 0xe1, 0x93, 0x56, 0x38, 0x45, 0xd6, 0xe3, 0xe1, + 0xd4, 0xa5, 0xe2, 0x24, 0xc4, 0x10, 0x7b, 0x29, 0xc3, 0xd8, 0x85, 0xda, 0x98, 0x7a, 0x73, 0x13, + 0x4f, 0x42, 0xe4, 0x82, 0xe8, 0x50, 0x76, 0x91, 0x73, 0x7b, 0x8e, 0xba, 0xd6, 0xd6, 0xba, 0x55, + 0x33, 0x09, 0x8d, 0x73, 0x0d, 0xea, 0x31, 0x93, 0x07, 0xbe, 0xc7, 0xf1, 0x7a, 0x2a, 0xf9, 0x0b, + 0xea, 0x1c, 0xd9, 0x29, 0x9d, 0xa1, 0xe5, 0xd9, 0x2e, 0xea, 0x39, 0xb9, 0x5c, 0x53, 0xd8, 0x33, + 0xdb, 0x45, 0xb2, 0x05, 0x55, 0x41, 0x5d, 0xe4, 0xc2, 0x76, 0x03, 0x3d, 0xdf, 0xd6, 0xba, 0x79, + 0x73, 0x09, 0x90, 0x16, 0x54, 0x8e, 0x7c, 0x2e, 0xa4, 0xb8, 0x20, 0xc5, 0x69, 0x6c, 0x74, 0xa0, + 0x31, 0xf2, 0xe6, 0xc8, 0x45, 0x62, 0xf9, 0x37, 0x28, 0xca, 0xa2, 0x94, 0x8b, 0x38, 0x30, 0xda, + 0xd0, 0x4c, 0x68, 0xca, 0x6f, 0x13, 0x72, 0xd4, 0x51, 0xa4, 0x1c, 0x75, 0x8c, 0x8f, 0x1a, 0xfc, + 0xfd, 0x04, 0x93, 0x34, 0x07, 0x94, 0x0b, 0x9f, 0x2d, 0x86, 0x0b, 0x15, 0x8f, 0xf6, 0x33, 0xf3, + 0x93, 0x6d, 0x00, 0x16, 0x13, 0x2c, 0xea, 0xa8, 0x0a, 0xab, 0x0a, 0x19, 0x39, 0xe4, 0x4f, 0xa8, + 0x06, 0xf6, 0x1c, 0x2d, 0x4e, 0xcf, 0x50, 0xd6, 0x57, 0x34, 0x2b, 0x11, 0x30, 0xa1, 0x67, 0x52, + 0x2b, 0x17, 0x85, 0xff, 0x1a, 0x3d, 0x55, 0xa0, 0xa4, 0x3f, 0x8f, 0x00, 0xe3, 0xad, 0x06, 0xdb, + 0x57, 0x18, 0x3b, 0x34, 0x47, 0xd9, 0x96, 0x36, 0x20, 0x1f, 0x32, 0xaa, 0xbc, 0x44, 0x9f, 0x3f, + 0xe5, 0x62, 0x0f, 0x36, 0x5e, 0xd8, 0xc7, 0xd4, 0xb1, 0x05, 0xf5, 0x3d, 0x13, 0x79, 0x78, 0x2c, + 0xc8, 0x26, 0x94, 0x1c, 0x9c, 0x33, 0x8c, 0x37, 0xd6, 0x4c, 0x15, 0x19, 0x5f, 0x72, 0x50, 0x57, + 0x3e, 0x1f, 0x7b, 0x82, 0x2d, 0xc8, 0x1f, 0x50, 0xc1, 0xe8, 0xc3, 0x4a, 0x3b, 0x5e, 0x96, 0xf1, + 0xc8, 0x89, 0x86, 0x23, 0x3d, 0x68, 0xcb, 0xe5, 0xd2, 0x6e, 0xde, 0xac, 0xa5, 0xd8, 0x53, 0x4e, + 0x3a, 0xd0, 0x48, 0x7a, 0xcb, 0x85, 0x2d, 0x62, 0xeb, 0xd5, 0x83, 0x35, 0xb3, 0xae, 0xe0, 0x49, + 0x84, 0x92, 0x4d, 0x28, 0xe2, 0x29, 0x7a, 0x22, 0xf6, 0x7e, 0xb0, 0x66, 0xc6, 0x21, 0xb9, 0x07, + 0x3a, 0x0f, 0x03, 0x64, 0x1c, 0x1d, 0x74, 0xac, 0xe9, 0xc2, 0x5a, 0x39, 0xa8, 0xa2, 0x34, 0xf3, + 0xfb, 0x72, 0x7d, 0x79, 0xe0, 0x4e, 0xe4, 0x7a, 0x1a, 0xd2, 0x63, 0x27, 0x22, 0x96, 0x62, 0xd7, + 0x32, 0x1e, 0x39, 0xa4, 0x03, 0x4d, 0x3f, 0x14, 0x33, 0xdf, 0x45, 0x8b, 0xa1, 0xcd, 0x7d, 0x4f, + 0x2f, 0x4b, 0x42, 0x43, 0xa1, 0xa6, 0x04, 0xc9, 0x3e, 0x94, 0x98, 0x6c, 0x95, 0x5e, 0x69, 0x6b, + 0xdd, 0xda, 0xe0, 0xff, 0xde, 0xf5, 0x57, 0xaf, 0x77, 0xb9, 0xbd, 0xa6, 0xd2, 0x0e, 0xeb, 0x00, + 0xfe, 0x6c, 0x16, 0x32, 0x86, 0xde, 0x0c, 0x8d, 0xcf, 0x1a, 0x34, 0x2f, 0xce, 0xc2, 0xa5, 0xe1, + 0xd3, 0x2e, 0x0f, 0xdf, 0xb7, 0x83, 0xd0, 0x81, 0x66, 0x5c, 0x19, 0x17, 0xcc, 0x16, 0x38, 0x5f, + 0xc4, 0x2d, 0x35, 0x1b, 0x12, 0x9d, 0x28, 0x50, 0x36, 0xc0, 0xe6, 0x68, 0x45, 0xea, 0x82, 0x6a, + 0x80, 0xcd, 0xf1, 0x90, 0x51, 0x32, 0x04, 0x79, 0x82, 0x14, 0xb9, 0x5e, 0x6c, 0xe7, 0xbb, 0xb5, + 0x41, 0x37, 0xab, 0xb4, 0xd5, 0x61, 0x30, 0x13, 0xa1, 0xf1, 0x41, 0x83, 0x7f, 0xb2, 0x6f, 0x9c, + 0xba, 0xaa, 0xfb, 0x50, 0x3e, 0x8a, 0x57, 0x65, 0x71, 0xb5, 0xc1, 0x5e, 0xd6, 0x66, 0x17, 0xf3, + 0x99, 0x89, 0x94, 0xfc, 0x0b, 0xeb, 0x1e, 0xbe, 0x11, 0xd6, 0xca, 0x94, 0xc7, 0x2d, 0x69, 0x44, + 0xf0, 0x38, 0x9d, 0xf4, 0x77, 0x1a, 0xec, 0x5c, 0x77, 0xdf, 0x7e, 0x85, 0xa1, 0xc1, 0x79, 0x01, + 0xaa, 0x93, 0x24, 0x1b, 0x79, 0x05, 0x85, 0xe8, 0xdd, 0x25, 0xbb, 0x59, 0x5b, 0xae, 0xbc, 0xe1, + 0xad, 0xee, 0xf7, 0x89, 0x71, 0x59, 0xc6, 0x1a, 0xb1, 0xa1, 0x14, 0x3f, 0x93, 0xe4, 0xbf, 0x2c, + 0xd5, 0x85, 0x17, 0xb7, 0xb5, 0x77, 0x13, 0x6a, 0xba, 0xc5, 0x27, 0x0d, 0xb6, 0xb2, 0x4e, 0x9d, + 0x3c, 0xcc, 0x4a, 0x77, 0x83, 0x17, 0xba, 0xf5, 0xe8, 0xf6, 0x09, 0x52, 0x97, 0xef, 0x35, 0xd8, + 0xbc, 0x7a, 0x08, 0xc8, 0xfd, 0x1f, 0x4c, 0xbf, 0x7c, 0xa8, 0x5b, 0x0f, 0x6e, 0x23, 0x4d, 0x3c, + 0x0d, 0x11, 0x76, 0x66, 0xbe, 0x9b, 0x91, 0x62, 0xd8, 0x4c, 0xc7, 0x64, 0x1c, 0xfd, 0xd2, 0x8f, + 0xb5, 0x97, 0x77, 0xe6, 0x54, 0x1c, 0x85, 0xd3, 0xde, 0xcc, 0x77, 0xfb, 0x91, 0xb0, 0xbf, 0x22, + 0xec, 0xdb, 0x01, 0xed, 0xa7, 0xe2, 0xbe, 0xfc, 0x73, 0x10, 0x4c, 0xa7, 0x25, 0xf9, 0x71, 0xf7, + 0x6b, 0x00, 0x00, 0x00, 0xff, 0xff, 0x18, 0xd9, 0x72, 0xef, 0x38, 0x08, 0x00, 0x00, }, } diff --git a/api/stovepipe/protopb/stovepipe_grpc.pb.go b/api/stovepipe/protopb/stovepipe_grpc.pb.go index ec4f58a47..bf75ff528 100644 --- a/api/stovepipe/protopb/stovepipe_grpc.pb.go +++ b/api/stovepipe/protopb/stovepipe_grpc.pb.go @@ -34,8 +34,10 @@ import ( const _ = grpc.SupportPackageIsVersion9 const ( - Stovepipe_Ping_FullMethodName = "/uber.submitqueue.stovepipe.Stovepipe/Ping" - Stovepipe_Ingest_FullMethodName = "/uber.submitqueue.stovepipe.Stovepipe/Ingest" + Stovepipe_Ping_FullMethodName = "/uber.submitqueue.stovepipe.Stovepipe/Ping" + Stovepipe_Ingest_FullMethodName = "/uber.submitqueue.stovepipe.Stovepipe/Ingest" + Stovepipe_GetRequestHistoryByRequestID_FullMethodName = "/uber.submitqueue.stovepipe.Stovepipe/GetRequestHistoryByRequestID" + Stovepipe_GetRequestHistoryByURI_FullMethodName = "/uber.submitqueue.stovepipe.Stovepipe/GetRequestHistoryByURI" ) // StovepipeClient is the client API for Stovepipe service. @@ -49,6 +51,10 @@ type StovepipeClient interface { // Ingest admits a queue's newly observed commit into the validation pipeline and returns // the minted request ID. The caller hands off asynchronously; validation happens later. Ingest(ctx context.Context, in *IngestRequest, opts ...grpc.CallOption) (*IngestResponse, error) + // GetRequestHistoryByRequestID returns retained history for one request ID. + GetRequestHistoryByRequestID(ctx context.Context, in *GetRequestHistoryByRequestIDRequest, opts ...grpc.CallOption) (*GetRequestHistoryByRequestIDResponse, error) + // GetRequestHistoryByURI returns retained history for an exact commit URI's authoritative request. + GetRequestHistoryByURI(ctx context.Context, in *GetRequestHistoryByURIRequest, opts ...grpc.CallOption) (*GetRequestHistoryByURIResponse, error) } type stovepipeClient struct { @@ -79,6 +85,26 @@ func (c *stovepipeClient) Ingest(ctx context.Context, in *IngestRequest, opts .. return out, nil } +func (c *stovepipeClient) GetRequestHistoryByRequestID(ctx context.Context, in *GetRequestHistoryByRequestIDRequest, opts ...grpc.CallOption) (*GetRequestHistoryByRequestIDResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetRequestHistoryByRequestIDResponse) + err := c.cc.Invoke(ctx, Stovepipe_GetRequestHistoryByRequestID_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *stovepipeClient) GetRequestHistoryByURI(ctx context.Context, in *GetRequestHistoryByURIRequest, opts ...grpc.CallOption) (*GetRequestHistoryByURIResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetRequestHistoryByURIResponse) + err := c.cc.Invoke(ctx, Stovepipe_GetRequestHistoryByURI_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + // StovepipeServer is the server API for Stovepipe service. // All implementations must embed UnimplementedStovepipeServer // for forward compatibility. @@ -90,6 +116,10 @@ type StovepipeServer interface { // Ingest admits a queue's newly observed commit into the validation pipeline and returns // the minted request ID. The caller hands off asynchronously; validation happens later. Ingest(context.Context, *IngestRequest) (*IngestResponse, error) + // GetRequestHistoryByRequestID returns retained history for one request ID. + GetRequestHistoryByRequestID(context.Context, *GetRequestHistoryByRequestIDRequest) (*GetRequestHistoryByRequestIDResponse, error) + // GetRequestHistoryByURI returns retained history for an exact commit URI's authoritative request. + GetRequestHistoryByURI(context.Context, *GetRequestHistoryByURIRequest) (*GetRequestHistoryByURIResponse, error) mustEmbedUnimplementedStovepipeServer() } @@ -106,6 +136,12 @@ func (UnimplementedStovepipeServer) Ping(context.Context, *PingRequest) (*PingRe func (UnimplementedStovepipeServer) Ingest(context.Context, *IngestRequest) (*IngestResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Ingest not implemented") } +func (UnimplementedStovepipeServer) GetRequestHistoryByRequestID(context.Context, *GetRequestHistoryByRequestIDRequest) (*GetRequestHistoryByRequestIDResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetRequestHistoryByRequestID not implemented") +} +func (UnimplementedStovepipeServer) GetRequestHistoryByURI(context.Context, *GetRequestHistoryByURIRequest) (*GetRequestHistoryByURIResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetRequestHistoryByURI not implemented") +} func (UnimplementedStovepipeServer) mustEmbedUnimplementedStovepipeServer() {} func (UnimplementedStovepipeServer) testEmbeddedByValue() {} @@ -163,6 +199,42 @@ func _Stovepipe_Ingest_Handler(srv interface{}, ctx context.Context, dec func(in return interceptor(ctx, in, info, handler) } +func _Stovepipe_GetRequestHistoryByRequestID_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetRequestHistoryByRequestIDRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StovepipeServer).GetRequestHistoryByRequestID(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Stovepipe_GetRequestHistoryByRequestID_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StovepipeServer).GetRequestHistoryByRequestID(ctx, req.(*GetRequestHistoryByRequestIDRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Stovepipe_GetRequestHistoryByURI_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetRequestHistoryByURIRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StovepipeServer).GetRequestHistoryByURI(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Stovepipe_GetRequestHistoryByURI_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StovepipeServer).GetRequestHistoryByURI(ctx, req.(*GetRequestHistoryByURIRequest)) + } + return interceptor(ctx, in, info, handler) +} + // Stovepipe_ServiceDesc is the grpc.ServiceDesc for Stovepipe service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -178,6 +250,14 @@ var Stovepipe_ServiceDesc = grpc.ServiceDesc{ MethodName: "Ingest", Handler: _Stovepipe_Ingest_Handler, }, + { + MethodName: "GetRequestHistoryByRequestID", + Handler: _Stovepipe_GetRequestHistoryByRequestID_Handler, + }, + { + MethodName: "GetRequestHistoryByURI", + Handler: _Stovepipe_GetRequestHistoryByURI_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "stovepipe.proto", diff --git a/doc/rfc/stovepipe/request-history-api.md b/doc/rfc/stovepipe/request-history-api.md index babb6081b..44225ce0a 100644 --- a/doc/rfc/stovepipe/request-history-api.md +++ b/doc/rfc/stovepipe/request-history-api.md @@ -2,7 +2,7 @@ ## Summary -Stovepipe exposes retained request history through queue-scoped point lookups by request ID and exact URI. Both selectors return the same ordered, cursor-paginated history. +Stovepipe exposes retained request history through queue-scoped point lookups by request ID and exact URI. URI lookup resolves the newest authoritative request for that commit. Both selectors return the same ordered, cursor-paginated history. The API reads the append-only model defined by [Stovepipe Request Event History](request-event-history.md) directly. It does not replay history into current state or introduce a second persisted history projection. Current commit status remains a separate read concern derived from operational entities rather than request history. @@ -15,7 +15,7 @@ The API supports the same selectors as [SubmitQueue Gateway Request History APIs Both methods require a queue because Stovepipe storage and authorization are queue-scoped. A selector belonging to another queue is not found rather than resolved across shards. -SubmitQueue's URI method returns several histories because the same change may be submitted repeatedly. Stovepipe ingest permanently deduplicates `(queue, URI)` to one request, so its URI method returns exactly one history. Relaxing that invariant later would require a new plural method rather than changing this method's cardinality in place. +SubmitQueue's URI method returns several histories because the same change may be submitted repeatedly. Stovepipe's URI method instead returns exactly one history: the request selected by the queue's durable authoritative mapping for that URI. The current insert-once mapping selects the only request; future revalidation advances the mapping to the newest accepted request without changing this API's cardinality. Older attempts remain addressable by request ID, and discovering every attempt can be added later as a separate list API. ## Representative Contract @@ -41,7 +41,7 @@ message ValidationResult { } message HistoryEntry { - string id = 1; + string entry_id = 1; int64 timestamp_ms = 2; oneof occurrence { string request_state = 3; @@ -83,9 +83,9 @@ Entry IDs and page tokens are opaque. Clients may compare entry IDs and pass pag Request-ID lookup validates the queue, ID, page size, and optional token; loads the queue's `Request` to validate the selector and supply immutable wrapper context; and lists one bounded page of its `RequestHistoryStore` entries. -URI lookup resolves the existing `RequestURIStore` primary key and delegates to the same paginated request-ID path. It does not scan history by an entry's `URI` field and requires no new storage index. A missing mapping is not found; a mapping whose Request is missing is an internal consistency error. +URI lookup resolves the authoritative request ID from the existing `RequestURIStore` primary key and delegates to the same paginated request-ID path. Authority is explicit stored state rather than a timestamp comparison. The current mapping is insert-once; supporting revalidation later requires a versioned conditional update that advances it only after the newer Request is durable. It does not scan history by an entry's `URI` field and requires no new storage index. A missing mapping is not found; a mapping whose Request is missing is an internal consistency error. -The request-URI mapping must be repaired and retained with its Request and history. Otherwise URI lookup could lose coverage while request-ID lookup still succeeds. The loaded Request supplies URI, build strategy, and base URI once on the `RequestHistory` wrapper; these immutable values are not duplicated on every entry. +The request-URI mapping must be repaired and retained with its Request and history. Otherwise URI lookup could lose coverage while request-ID lookup still succeeds. Once a newer request becomes authoritative, a later failure does not fall back to an older successful attempt. The loaded Request supplies URI, build strategy, and base URI once on the `RequestHistory` wrapper; these immutable values are not duplicated on every entry. ## Public Projection @@ -133,7 +133,7 @@ Request-ID and URI lookup return the same stored entries, ordering, and paginati The public shape follows SubmitQueue's queue `List` convention: an empty token selects the first page, zero page size selects the server default, and the response returns an opaque `next_page_token` that is empty on the last page. The initial default is 50 entries and the maximum is 200. The controller requests one more entry than the effective page size, returns only the requested page, and issues a token only when the extra entry proves that another page exists. -Pagination uses the immutable keyset `(timestamp_ms ASC, entry_id ASC)`. The versioned token represents the last returned ordering tuple and is bound to the original selector kind and value, queue, and resolved request ID. The binding does not prescribe whether those values are embedded or fingerprinted in the token. Reusing a token with another method, queue, request ID, or URI is invalid. Page size is not bound into the token, so a caller may change it between pages within the server maximum. The controller decodes the public token into the storage contract's typed exclusive cursor; storage implementations never parse wire tokens. +Pagination uses the immutable keyset `(timestamp_ms ASC, entry_id ASC)`. The versioned token represents the last returned ordering tuple and is bound to the original selector kind and value, queue, and resolved request ID. Binding URI pagination to the resolved request ID keeps an in-progress traversal on the same history if a newer request becomes authoritative between pages. The binding does not prescribe whether those values are embedded or fingerprinted in the token. Reusing a token with another method, queue, request ID, or URI is invalid. Page size is not bound into the token, so a caller may change it between pages within the server maximum. The controller decodes the public token into the storage contract's typed exclusive cursor; storage implementations never parse wire tokens. Tokens are traversal cursors rather than snapshot handles. A new occurrence ordered after the cursor can appear on a later page. A repair that inserts an older occurrence at or before an already-consumed cursor may be observed only by starting a fresh traversal. This is the paginated form of the API's existing eventual-consistency guarantee: a token prevents duplicates from stable retained entries but does not freeze history while pipeline writers and repair are active. @@ -177,7 +177,7 @@ Rejected because it would add query-by-attribute capability to `RequestHistorySt ### Return several histories by URI -Rejected while ingest enforces one request per `(queue, URI)`. A repeated field would imply cardinality the domain does not permit and make a future deduplication change silently alter existing responses. +Rejected because URI lookup answers which request is authoritative for the commit. Returning every attempt would mix audit discovery with one request's independently paginated history. A future attempt-listing API can return request IDs without changing this point lookup. ### Return every entry in one response