Skip to content

Commit 8c0dda7

Browse files
committed
feat(metric): model trigger table record api
1 parent 89cce72 commit 8c0dda7

File tree

7 files changed

+272
-3
lines changed

7 files changed

+272
-3
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ require (
1616
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1
1717
github.com/iancoleman/strcase v0.2.0
1818
github.com/influxdata/influxdb-client-go/v2 v2.12.3
19-
github.com/instill-ai/protogen-go v0.3.3-alpha.0.20241029162707-1398399a24ee
19+
github.com/instill-ai/protogen-go v0.3.3-alpha.0.20241104034549-4b92cf27ff00
2020
github.com/instill-ai/usage-client v0.2.4-alpha.0.20240123081026-6c78d9a5197a
2121
github.com/instill-ai/x v0.4.0-alpha
2222
github.com/knadh/koanf v1.5.0

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1090,8 +1090,8 @@ github.com/influxdata/influxdb-client-go/v2 v2.12.3 h1:28nRlNMRIV4QbtIUvxhWqaxn0
10901090
github.com/influxdata/influxdb-client-go/v2 v2.12.3/go.mod h1:IrrLUbCjjfkmRuaCiGQg4m2GbkaeJDcuWoxiWdQEbA0=
10911091
github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 h1:W9WBk7wlPfJLvMCdtV4zPulc4uCPrlywQOmbFOhgQNU=
10921092
github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo=
1093-
github.com/instill-ai/protogen-go v0.3.3-alpha.0.20241029162707-1398399a24ee h1:onnzrn5jabO3jDLPo2193Ql6YMRyDWDx9K834Bfi8V0=
1094-
github.com/instill-ai/protogen-go v0.3.3-alpha.0.20241029162707-1398399a24ee/go.mod h1:rf0UY7VpEgpaLudYEcjx5rnbuwlBaaLyD4FQmWLtgAY=
1093+
github.com/instill-ai/protogen-go v0.3.3-alpha.0.20241104034549-4b92cf27ff00 h1:65aiWEWp8ayWm64aCfa7nOoNSjsiX6zXs1VBadJ/JhY=
1094+
github.com/instill-ai/protogen-go v0.3.3-alpha.0.20241104034549-4b92cf27ff00/go.mod h1:rf0UY7VpEgpaLudYEcjx5rnbuwlBaaLyD4FQmWLtgAY=
10951095
github.com/instill-ai/usage-client v0.2.4-alpha.0.20240123081026-6c78d9a5197a h1:gmy8BcCFDZQan40c/D3f62DwTYtlCwi0VrSax+pKffw=
10961096
github.com/instill-ai/usage-client v0.2.4-alpha.0.20240123081026-6c78d9a5197a/go.mod h1:EpX3Yr661uWULtZf5UnJHfr5rw2PDyX8ku4Kx0UtYFw=
10971097
github.com/instill-ai/x v0.4.0-alpha h1:zQV2VLbSHjMv6gyBN/2mwwrvWk0/mJM6ZKS12AzjfQg=

pkg/constant/constant.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ const (
4141
PipelineUID string = "pipeline_uid"
4242
PipelineReleaseID string = "pipeline_release_id"
4343
PipelineReleaseUID string = "pipeline_release_uid"
44+
ModelID string = "model_id"
45+
ModelUID string = "model_uid"
4446
TriggerMode string = "trigger_mode"
4547
Status string = "status"
4648
)

pkg/handler/publichandler.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -979,6 +979,70 @@ func (h *PublicHandler) ListPipelineTriggerTableRecords(ctx context.Context, req
979979
return &resp, nil
980980
}
981981

982+
func (h *PublicHandler) ListModelTriggerTableRecords(ctx context.Context, req *mgmtPB.ListModelTriggerTableRecordsRequest) (*mgmtPB.ListModelTriggerTableRecordsResponse, error) {
983+
984+
eventName := "ListModelTriggerTableRecords"
985+
ctx, span := tracer.Start(ctx, eventName,
986+
trace.WithSpanKind(trace.SpanKindServer))
987+
defer span.End()
988+
989+
logUUID, _ := uuid.NewV4()
990+
991+
logger, _ := logger.GetZapLogger(ctx)
992+
993+
ctxUserUID, err := h.Service.ExtractCtxUser(ctx, false)
994+
if err != nil {
995+
span.SetStatus(1, err.Error())
996+
return nil, err
997+
}
998+
pbUser, err := h.Service.GetUserByUIDAdmin(ctx, ctxUserUID)
999+
if err != nil {
1000+
span.SetStatus(1, err.Error())
1001+
return nil, err
1002+
}
1003+
1004+
declarations, err := filtering.NewDeclarations([]filtering.DeclarationOption{
1005+
filtering.DeclareStandardFunctions(),
1006+
filtering.DeclareIdent(constant.Start, filtering.TypeTimestamp),
1007+
filtering.DeclareIdent(constant.Stop, filtering.TypeTimestamp),
1008+
filtering.DeclareIdent(strcase.ToLowerCamel(constant.OwnerName), filtering.TypeString),
1009+
filtering.DeclareIdent(strcase.ToLowerCamel(constant.ModelID), filtering.TypeString),
1010+
filtering.DeclareIdent(strcase.ToLowerCamel(constant.ModelUID), filtering.TypeString),
1011+
}...)
1012+
if err != nil {
1013+
span.SetStatus(1, err.Error())
1014+
return nil, err
1015+
}
1016+
1017+
filter, err := filtering.ParseFilter(req, declarations)
1018+
if err != nil {
1019+
span.SetStatus(1, err.Error())
1020+
return nil, err
1021+
}
1022+
1023+
modelTriggerTableRecords, totalSize, nextPageToken, err := h.Service.ListModelTriggerTableRecords(ctx, pbUser, int64(req.GetPageSize()), req.GetPageToken(), filter)
1024+
if err != nil {
1025+
span.SetStatus(1, err.Error())
1026+
return nil, err
1027+
}
1028+
1029+
resp := mgmtPB.ListModelTriggerTableRecordsResponse{
1030+
ModelTriggerTableRecords: modelTriggerTableRecords,
1031+
NextPageToken: nextPageToken,
1032+
TotalSize: int32(totalSize),
1033+
}
1034+
1035+
logger.Info(string(custom_otel.NewLogMessage(
1036+
span,
1037+
logUUID.String(),
1038+
uuid.FromStringOrNil(*pbUser.Uid),
1039+
eventName,
1040+
custom_otel.SetEventResult(fmt.Sprintf("Total records retrieved: %v", totalSize)),
1041+
)))
1042+
1043+
return &resp, nil
1044+
}
1045+
9821046
// ListPipelineTriggerChartRecords returns a timeline of a requester's pipeline
9831047
// trigger count.
9841048
func (h *PublicHandler) ListPipelineTriggerChartRecords(ctx context.Context, req *mgmtPB.ListPipelineTriggerChartRecordsRequest) (*mgmtPB.ListPipelineTriggerChartRecordsResponse, error) {

pkg/repository/influx.go

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ var defaultAggregationWindow = time.Hour.Nanoseconds()
3434
type InfluxDB interface {
3535
QueryPipelineTriggerRecords(ctx context.Context, owner string, ownerQueryString string, pageSize int64, pageToken string, filter filtering.Filter) (pipelines []*mgmtpb.PipelineTriggerRecord, totalSize int64, nextPageToken string, err error)
3636
QueryPipelineTriggerTableRecords(ctx context.Context, owner string, ownerQueryString string, pageSize int64, pageToken string, filter filtering.Filter) (records []*mgmtpb.PipelineTriggerTableRecord, totalSize int64, nextPageToken string, err error)
37+
QueryModelTriggerTableRecords(ctx context.Context, owner string, ownerQueryString string, pageSize int64, pageToken string, filter filtering.Filter) (records []*mgmtpb.ModelTriggerTableRecord, totalSize int64, nextPageToken string, err error)
3738
QueryPipelineTriggerChartRecords(ctx context.Context, owner string, ownerQueryString string, aggregationWindow int64, filter filtering.Filter) (records []*mgmtpb.PipelineTriggerChartRecord, err error)
3839
ListModelTriggerChartRecords(ctx context.Context, p ListModelTriggerChartRecordsParams) (*mgmtpb.ListModelTriggerChartRecordsResponse, error)
3940

@@ -121,6 +122,192 @@ func AggregationWindowOffset(t time.Time) time.Duration {
121122
return t.Sub(startOfDay)
122123
}
123124

125+
func (i *influxDB) QueryModelTriggerTableRecords(ctx context.Context, owner string, ownerQueryString string,
126+
pageSize int64, pageToken string, filter filtering.Filter) (records []*mgmtpb.ModelTriggerTableRecord,
127+
totalSize int64, nextPageToken string, err error) {
128+
129+
logger, _ := logger.GetZapLogger(ctx)
130+
131+
if pageSize == 0 {
132+
pageSize = DefaultPageSize
133+
} else if pageSize > MaxPageSize {
134+
pageSize = MaxPageSize
135+
}
136+
137+
start := time.Time{}.Format(time.RFC3339Nano)
138+
stop := time.Now().Format(time.RFC3339Nano)
139+
mostRecetTimeFilter := time.Now().Format(time.RFC3339Nano)
140+
141+
// TODO: validate owner uid from token
142+
if pageToken != "" {
143+
mostRecetTime, _, err := paginate.DecodeToken(pageToken)
144+
if err != nil {
145+
return nil, 0, "", status.Errorf(codes.InvalidArgument, "Invalid page token: %s", err.Error())
146+
}
147+
mostRecetTime = mostRecetTime.Add(time.Duration(-1))
148+
mostRecetTimeFilter = mostRecetTime.Format(time.RFC3339Nano)
149+
}
150+
151+
// TODO: design better filter expression to flux transpiler
152+
expr, err := i.transpileFilter(filter)
153+
if err != nil {
154+
return nil, 0, "", status.Error(codes.Internal, err.Error())
155+
}
156+
157+
if expr != "" {
158+
exprs := strings.Split(expr, "&&")
159+
for i, expr := range exprs {
160+
if strings.HasPrefix(expr, constant.Start) {
161+
start = strings.Split(expr, "@")[1]
162+
exprs[i] = ""
163+
}
164+
if strings.HasPrefix(expr, constant.Stop) {
165+
stop = strings.Split(expr, "@")[1]
166+
exprs[i] = ""
167+
}
168+
}
169+
expr = strings.Join(exprs, "")
170+
}
171+
172+
baseQuery := fmt.Sprintf(
173+
`base =
174+
from(bucket: "%v")
175+
|> range(start: %v, stop: %v)
176+
|> filter(fn: (r) => r["_measurement"] == "model.trigger.v1")
177+
|> pivot(rowKey: ["_time"], columnKey: ["_field"], valueColumn: "_value")
178+
%v
179+
%v
180+
triggerRank =
181+
base
182+
|> drop(
183+
columns: [
184+
"owner_uid",
185+
"trigger_mode",
186+
"compute_time_duration",
187+
"model_trigger_id",
188+
"status",
189+
],
190+
)
191+
|> group(columns: ["model_uid"])
192+
|> map(fn: (r) => ({r with trigger_time: time(v: r.trigger_time)}))
193+
|> sort(columns: ["trigger_time"], desc: true)
194+
|> first(column: "trigger_time")
195+
|> rename(columns: {trigger_time: "most_recent_trigger_time"})
196+
triggerCount =
197+
base
198+
|> drop(
199+
columns: ["owner_uid", "trigger_mode", "compute_time_duration", "model_trigger_id"],
200+
)
201+
|> group(columns: ["model_uid", "status"])
202+
|> count(column: "trigger_time")
203+
|> rename(columns: {trigger_time: "trigger_count"})
204+
|> group(columns: ["model_uid"])
205+
triggerTable =
206+
join(tables: {t1: triggerRank, t2: triggerCount}, on: ["model_uid"])
207+
|> group()
208+
|> pivot(
209+
rowKey: ["model_uid", "most_recent_trigger_time"],
210+
columnKey: ["status"],
211+
valueColumn: "trigger_count",
212+
)
213+
|> filter(
214+
fn: (r) => r["most_recent_trigger_time"] < time(v: %v)
215+
)
216+
nameMap =
217+
base
218+
|> keep(columns: ["trigger_time", "model_id", "model_uid"])
219+
|> group(columns: ["model_uid"])
220+
|> top(columns: ["trigger_time"], n: 1)
221+
|> drop(columns: ["trigger_time"])
222+
|> group()
223+
join(tables: {t1: triggerTable, t2: nameMap}, on: ["model_uid"])`,
224+
i.bucket,
225+
start,
226+
stop,
227+
ownerQueryString,
228+
expr,
229+
mostRecetTimeFilter,
230+
)
231+
232+
query := fmt.Sprintf(
233+
`%v
234+
|> group()
235+
|> sort(columns: ["most_recent_trigger_time"], desc: true)
236+
|> limit(n: %v)`,
237+
baseQuery,
238+
pageSize,
239+
)
240+
241+
totalQuery := fmt.Sprintf(
242+
`%v
243+
|> group()
244+
|> count(column: "model_uid")`,
245+
baseQuery,
246+
)
247+
248+
var lastTimestamp time.Time
249+
250+
result, err := i.api.Query(ctx, query)
251+
if err != nil {
252+
return nil, 0, "", status.Errorf(codes.InvalidArgument, "Invalid query: %s", err.Error())
253+
} else {
254+
// Iterate over query response
255+
for result.Next() {
256+
// Notice when group key has changed
257+
if result.TableChanged() {
258+
logger.Debug(fmt.Sprintf("table: %s\n", result.TableMetadata().String()))
259+
}
260+
261+
tableRecord := &mgmtpb.ModelTriggerTableRecord{}
262+
263+
if v, match := result.Record().ValueByKey(constant.ModelID).(string); match {
264+
tableRecord.ModelId = v
265+
}
266+
if v, match := result.Record().ValueByKey(constant.ModelUID).(string); match {
267+
tableRecord.ModelUid = v
268+
}
269+
if v, match := result.Record().ValueByKey(mgmtpb.Status_STATUS_COMPLETED.String()).(int64); match {
270+
tableRecord.TriggerCountCompleted = int32(v)
271+
}
272+
if v, match := result.Record().ValueByKey(mgmtpb.Status_STATUS_ERRORED.String()).(int64); match {
273+
tableRecord.TriggerCountErrored = int32(v)
274+
}
275+
276+
records = append(records, tableRecord)
277+
}
278+
279+
// Check for an error
280+
if result.Err() != nil {
281+
return nil, 0, "", status.Errorf(codes.InvalidArgument, "Invalid query: %s", err.Error())
282+
}
283+
if result.Record() == nil {
284+
return nil, 0, "", nil
285+
}
286+
287+
if v, match := result.Record().ValueByKey("most_recent_trigger_time").(time.Time); match {
288+
lastTimestamp = v
289+
}
290+
}
291+
292+
var total int64
293+
totalQueryResult, err := i.api.Query(ctx, totalQuery)
294+
if err != nil {
295+
return nil, 0, "", status.Errorf(codes.InvalidArgument, "Invalid total query: %s", err.Error())
296+
} else {
297+
if totalQueryResult.Next() {
298+
total = totalQueryResult.Record().ValueByKey(constant.ModelUID).(int64)
299+
}
300+
}
301+
302+
if int64(len(records)) < total {
303+
pageToken = paginate.EncodeToken(lastTimestamp, owner)
304+
} else {
305+
pageToken = ""
306+
}
307+
308+
return records, int64(len(records)), pageToken, nil
309+
}
310+
124311
func (i *influxDB) QueryPipelineTriggerTableRecords(ctx context.Context, owner string, ownerQueryString string, pageSize int64, pageToken string, filter filtering.Filter) (records []*mgmtpb.PipelineTriggerTableRecord, totalSize int64, nextPageToken string, err error) {
125312

126313
logger, _ := logger.GetZapLogger(ctx)

pkg/service/metric.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,21 @@ func (s *service) ListPipelineTriggerTableRecords(ctx context.Context, owner *mg
144144
return pipelineTriggerTableRecords, ps, pt, nil
145145
}
146146

147+
func (s *service) ListModelTriggerTableRecords(ctx context.Context, owner *mgmtpb.User, pageSize int64, pageToken string, filter filtering.Filter) ([]*mgmtpb.ModelTriggerTableRecord, int64, string, error) {
148+
149+
ownerUID, _, _, ownerQueryString, filter, err := s.checkPipelineOwnership(ctx, filter, owner)
150+
if err != nil {
151+
return []*mgmtpb.ModelTriggerTableRecord{}, 0, "", err
152+
}
153+
154+
modelTriggerTableRecords, ps, pt, err := s.influxDB.QueryModelTriggerTableRecords(ctx, *ownerUID, ownerQueryString, pageSize, pageToken, filter)
155+
if err != nil {
156+
return nil, 0, "", err
157+
}
158+
159+
return modelTriggerTableRecords, ps, pt, nil
160+
}
161+
147162
func (s *service) ListPipelineTriggerChartRecords(ctx context.Context, owner *mgmtpb.User, aggregationWindow int64, filter filtering.Filter) ([]*mgmtpb.PipelineTriggerChartRecord, error) {
148163

149164
ownerUID, ownerID, ownerType, ownerQueryString, filter, err := s.checkPipelineOwnership(ctx, filter, owner)

pkg/service/service.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ type Service interface {
7373
ListPipelineTriggerRecords(ctx context.Context, owner *mgmtpb.User, pageSize int64, pageToken string, filter filtering.Filter) ([]*mgmtpb.PipelineTriggerRecord, int64, string, error)
7474
ListPipelineTriggerTableRecords(ctx context.Context, owner *mgmtpb.User, pageSize int64, pageToken string, filter filtering.Filter) ([]*mgmtpb.PipelineTriggerTableRecord, int64, string, error)
7575
ListPipelineTriggerChartRecords(ctx context.Context, owner *mgmtpb.User, aggregationWindow int64, filter filtering.Filter) ([]*mgmtpb.PipelineTriggerChartRecord, error)
76+
ListModelTriggerTableRecords(ctx context.Context, owner *mgmtpb.User, pageSize int64, pageToken string, filter filtering.Filter) ([]*mgmtpb.ModelTriggerTableRecord, int64, string, error)
7677
ListModelTriggerChartRecords(ctx context.Context, req *mgmtpb.ListModelTriggerChartRecordsRequest, ctxUserUID uuid.UUID) (*mgmtpb.ListModelTriggerChartRecordsResponse, error)
7778

7879
DBUser2PBUser(ctx context.Context, dbUser *datamodel.Owner) (*mgmtpb.User, error)

0 commit comments

Comments
 (0)