diff --git a/backend/controller/console/console.go b/backend/controller/console/console.go index efba2b5fa5..aec15d7357 100644 --- a/backend/controller/console/console.go +++ b/backend/controller/console/console.go @@ -638,13 +638,13 @@ func eventDALToProto(event timeline.Event) *pbtimeline.Event { sourceVerbRef = sourceVerb.ToProto().(*schemapb.Ref) //nolint:forcetypeassert } return &pbtimeline.Event{ - TimeStamp: timestamppb.New(event.Time), + Timestamp: timestamppb.New(event.Time), Id: event.ID, Entry: &pbtimeline.Event_Call{ Call: &pbtimeline.CallEvent{ RequestKey: requestKey, DeploymentKey: event.DeploymentKey.String(), - TimeStamp: timestamppb.New(event.Time), + Timestamp: timestamppb.New(event.Time), SourceVerbRef: sourceVerbRef, DestinationVerbRef: &schemapb.Ref{ Module: event.DestVerb.Module, @@ -666,13 +666,13 @@ func eventDALToProto(event timeline.Event) *pbtimeline.Event { requestKey = &rstr } return &pbtimeline.Event{ - TimeStamp: timestamppb.New(event.Time), + Timestamp: timestamppb.New(event.Time), Id: event.ID, Entry: &pbtimeline.Event_Log{ Log: &pbtimeline.LogEvent{ DeploymentKey: event.DeploymentKey.String(), RequestKey: requestKey, - TimeStamp: timestamppb.New(event.Time), + Timestamp: timestamppb.New(event.Time), LogLevel: event.Level, Attributes: event.Attributes, Message: event.Message, @@ -688,7 +688,7 @@ func eventDALToProto(event timeline.Event) *pbtimeline.Event { replaced = &rstr } return &pbtimeline.Event{ - TimeStamp: timestamppb.New(event.Time), + Timestamp: timestamppb.New(event.Time), Id: event.ID, Entry: &pbtimeline.Event_DeploymentCreated{ DeploymentCreated: &pbtimeline.DeploymentCreatedEvent{ @@ -702,7 +702,7 @@ func eventDALToProto(event timeline.Event) *pbtimeline.Event { } case *timeline.DeploymentUpdatedEvent: return &pbtimeline.Event{ - TimeStamp: timestamppb.New(event.Time), + Timestamp: timestamppb.New(event.Time), Id: event.ID, Entry: &pbtimeline.Event_DeploymentUpdated{ DeploymentUpdated: &pbtimeline.DeploymentUpdatedEvent{ @@ -721,7 +721,7 @@ func eventDALToProto(event timeline.Event) *pbtimeline.Event { } return &pbtimeline.Event{ - TimeStamp: timestamppb.New(event.Time), + Timestamp: timestamppb.New(event.Time), Id: event.ID, Entry: &pbtimeline.Event_Ingress{ Ingress: &pbtimeline.IngressEvent{ @@ -734,7 +734,7 @@ func eventDALToProto(event timeline.Event) *pbtimeline.Event { Method: event.Method, Path: event.Path, StatusCode: int32(event.StatusCode), - TimeStamp: timestamppb.New(event.Time), + Timestamp: timestamppb.New(event.Time), Duration: durationpb.New(event.Duration), Request: string(event.Request), RequestHeader: string(event.RequestHeader), @@ -747,7 +747,7 @@ func eventDALToProto(event timeline.Event) *pbtimeline.Event { case *timeline.CronScheduledEvent: return &pbtimeline.Event{ - TimeStamp: timestamppb.New(event.Time), + Timestamp: timestamppb.New(event.Time), Id: event.ID, Entry: &pbtimeline.Event_CronScheduled{ CronScheduled: &pbtimeline.CronScheduledEvent{ @@ -756,7 +756,7 @@ func eventDALToProto(event timeline.Event) *pbtimeline.Event { Module: event.Verb.Module, Name: event.Verb.Name, }, - TimeStamp: timestamppb.New(event.Time), + Timestamp: timestamppb.New(event.Time), Duration: durationpb.New(event.Duration), ScheduledAt: timestamppb.New(event.ScheduledAt), Schedule: event.Schedule, @@ -782,13 +782,13 @@ func eventDALToProto(event timeline.Event) *pbtimeline.Event { } return &pbtimeline.Event{ - TimeStamp: timestamppb.New(event.Time), + Timestamp: timestamppb.New(event.Time), Id: event.ID, Entry: &pbtimeline.Event_AsyncExecute{ AsyncExecute: &pbtimeline.AsyncExecuteEvent{ DeploymentKey: event.DeploymentKey.String(), RequestKey: requestKey, - TimeStamp: timestamppb.New(event.Time), + Timestamp: timestamppb.New(event.Time), AsyncEventType: asyncEventType, VerbRef: &schemapb.Ref{ Module: event.Verb.Module, @@ -807,14 +807,14 @@ func eventDALToProto(event timeline.Event) *pbtimeline.Event { } return &pbtimeline.Event{ - TimeStamp: timestamppb.New(event.Time), + Timestamp: timestamppb.New(event.Time), Id: event.ID, Entry: &pbtimeline.Event_PubsubPublish{ PubsubPublish: &pbtimeline.PubSubPublishEvent{ DeploymentKey: event.DeploymentKey.String(), RequestKey: requestKey, VerbRef: event.SourceVerb.ToProto().(*schemapb.Ref), //nolint:forcetypeassert - TimeStamp: timestamppb.New(event.Time), + Timestamp: timestamppb.New(event.Time), Duration: durationpb.New(event.Duration), Topic: event.Topic, Request: string(event.Request), @@ -837,7 +837,7 @@ func eventDALToProto(event timeline.Event) *pbtimeline.Event { } return &pbtimeline.Event{ - TimeStamp: timestamppb.New(event.Time), + Timestamp: timestamppb.New(event.Time), Id: event.ID, Entry: &pbtimeline.Event_PubsubConsume{ PubsubConsume: &pbtimeline.PubSubConsumeEvent{ @@ -845,7 +845,7 @@ func eventDALToProto(event timeline.Event) *pbtimeline.Event { RequestKey: requestKey, DestVerbModule: &destVerbModule, DestVerbName: &destVerbName, - TimeStamp: timestamppb.New(event.Time), + Timestamp: timestamppb.New(event.Time), Duration: durationpb.New(event.Duration), Topic: event.Topic, Error: event.Error.Ptr(), diff --git a/backend/controller/controller.go b/backend/controller/controller.go index f8b311d844..9b2494dc9d 100644 --- a/backend/controller/controller.go +++ b/backend/controller/controller.go @@ -51,6 +51,8 @@ import ( ftllease "github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/lease/v1" leaseconnect "github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/lease/v1/ftlv1connect" schemapb "github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/schema/v1" + timelinepb "github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/timeline/v1" + "github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/timeline/v1/timelinev1connect" ftlv1 "github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/v1" "github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/v1/ftlv1connect" frontend "github.com/TBD54566975/ftl/frontend/console" @@ -273,11 +275,11 @@ func New( timelineSvc := timeline.New(ctx, conn, encryption) svc.timeline = timelineSvc - pubSub := pubsub.New(ctx, conn, encryption, optional.Some[pubsub.AsyncCallListener](svc), timelineSvc) + pubSub := pubsub.New(ctx, conn, encryption, optional.Some[pubsub.AsyncCallListener](svc)) svc.pubSub = pubSub svc.dal = dal.New(ctx, conn, encryption, pubSub, svc.registry) - svc.deploymentLogsSink = newDeploymentLogsSink(ctx, timelineSvc) + svc.deploymentLogsSink = newDeploymentLogsSink(ctx) // Use min, max backoff if we are running in production, otherwise use // (1s, 1s) (or develBackoff). Will also wrap the job such that it its next @@ -1689,12 +1691,16 @@ func (s *Service) reapCallEvents(ctx context.Context) (time.Duration, error) { return time.Hour, nil } - removed, err := s.timeline.DeleteOldEvents(ctx, timeline.EventTypeCall, *s.config.EventLogRetention) + client := rpc.ClientFromContext[timelinev1connect.TimelineServiceClient](ctx) + resp, err := client.DeleteOldEvents(ctx, connect.NewRequest(&timelinepb.DeleteOldEventsRequest{ + EventType: timelinepb.EventType_EVENT_TYPE_CALL, + AgeSeconds: int64(s.config.EventLogRetention.Seconds()), + })) if err != nil { return 0, fmt.Errorf("failed to prune call events: %w", err) } - if removed > 0 { - logger.Debugf("Pruned %d call events older than %s", removed, s.config.EventLogRetention) + if resp.Msg.DeletedCount > 0 { + logger.Debugf("Pruned %d call events older than %s", resp.Msg.DeletedCount, s.config.EventLogRetention) } // Prune every 5% of the retention period. diff --git a/backend/controller/dal/async_calls_test.go b/backend/controller/dal/async_calls_test.go index 457bc7ec5e..5e678d9ef3 100644 --- a/backend/controller/dal/async_calls_test.go +++ b/backend/controller/dal/async_calls_test.go @@ -11,7 +11,6 @@ import ( "github.com/TBD54566975/ftl/backend/controller/encryption" "github.com/TBD54566975/ftl/backend/controller/pubsub" "github.com/TBD54566975/ftl/backend/controller/sql/sqltest" - "github.com/TBD54566975/ftl/backend/controller/timeline" "github.com/TBD54566975/ftl/backend/libdal" "github.com/TBD54566975/ftl/internal/log" "github.com/TBD54566975/ftl/internal/model" @@ -24,8 +23,7 @@ func TestNoCallToAcquire(t *testing.T) { encryption, err := encryption.New(ctx, conn, encryption.NewBuilder()) assert.NoError(t, err) - timelineSvc := timeline.New(ctx, conn, encryption) - pubSub := pubsub.New(ctx, conn, encryption, optional.None[pubsub.AsyncCallListener](), timelineSvc) + pubSub := pubsub.New(ctx, conn, encryption, optional.None[pubsub.AsyncCallListener]()) dal := New(ctx, conn, encryption, pubSub, nil) _, _, err = dal.AcquireAsyncCall(ctx) diff --git a/backend/controller/dal/dal.go b/backend/controller/dal/dal.go index 2f248047bb..45f0dbf6f7 100644 --- a/backend/controller/dal/dal.go +++ b/backend/controller/dal/dal.go @@ -16,11 +16,11 @@ import ( dalsql "github.com/TBD54566975/ftl/backend/controller/dal/internal/sql" dalmodel "github.com/TBD54566975/ftl/backend/controller/dal/model" "github.com/TBD54566975/ftl/backend/controller/encryption" - "github.com/TBD54566975/ftl/backend/controller/encryption/api" "github.com/TBD54566975/ftl/backend/controller/leases/dbleaser" "github.com/TBD54566975/ftl/backend/controller/pubsub" "github.com/TBD54566975/ftl/backend/controller/sql/sqltypes" "github.com/TBD54566975/ftl/backend/libdal" + "github.com/TBD54566975/ftl/backend/timeline" "github.com/TBD54566975/ftl/internal/log" "github.com/TBD54566975/ftl/internal/maps" "github.com/TBD54566975/ftl/internal/model" @@ -350,21 +350,11 @@ func (d *DAL) SetDeploymentReplicas(ctx context.Context, key model.DeploymentKey return libdal.TranslatePGError(err) } } - var payload api.EncryptedTimelineColumn - err = d.encryption.EncryptJSON(map[string]interface{}{ - "prev_min_replicas": deployment.MinReplicas, - "min_replicas": minReplicas, - }, &payload) - if err != nil { - return fmt.Errorf("failed to encrypt payload for InsertDeploymentUpdatedEvent: %w", err) - } - err = tx.db.InsertTimelineDeploymentUpdatedEvent(ctx, dalsql.InsertTimelineDeploymentUpdatedEventParams{ - DeploymentKey: key, - Payload: payload, + timeline.Publish(ctx, timeline.DeploymentUpdated{ + DeploymentKey: key, + MinReplicas: minReplicas, + PrevMinReplicas: int(deployment.MinReplicas), }) - if err != nil { - return libdal.TranslatePGError(err) - } return nil } @@ -420,25 +410,16 @@ func (d *DAL) ReplaceDeployment(ctx context.Context, newDeploymentKey model.Depl } } - var payload api.EncryptedTimelineColumn - err = d.encryption.EncryptJSON(map[string]any{ - "min_replicas": int32(minReplicas), - "replaced": replacedDeploymentKey, - }, &payload) - if err != nil { - return fmt.Errorf("replace deployment failed to encrypt payload: %w", err) - } - - err = tx.db.InsertTimelineDeploymentCreatedEvent(ctx, dalsql.InsertTimelineDeploymentCreatedEventParams{ - DeploymentKey: newDeploymentKey, - Language: newDeployment.Language, - ModuleName: newDeployment.ModuleName, - Payload: payload, + timeline.Publish(ctx, timeline.DeploymentCreated{ + DeploymentKey: newDeploymentKey, + Language: newDeployment.Language, + ModuleName: newDeployment.ModuleName, + MinReplicas: minReplicas, + ReplacedDeployment: replacedDeploymentKey, }) if err != nil { return fmt.Errorf("replace deployment failed to create event: %w", libdal.TranslatePGError(err)) } - return nil } diff --git a/backend/controller/dal/dal_test.go b/backend/controller/dal/dal_test.go index 9943ab676a..7ec1917fbc 100644 --- a/backend/controller/dal/dal_test.go +++ b/backend/controller/dal/dal_test.go @@ -3,6 +3,7 @@ package dal import ( "bytes" "context" + "net/http" "sync" "testing" "time" @@ -12,7 +13,7 @@ import ( "golang.org/x/sync/errgroup" "github.com/TBD54566975/ftl/backend/controller/artefacts" - "github.com/TBD54566975/ftl/backend/controller/timeline" + "github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/timeline/v1/timelinev1connect" dalmodel "github.com/TBD54566975/ftl/backend/controller/dal/model" "github.com/TBD54566975/ftl/backend/controller/encryption" @@ -21,18 +22,20 @@ import ( "github.com/TBD54566975/ftl/backend/libdal" "github.com/TBD54566975/ftl/internal/log" "github.com/TBD54566975/ftl/internal/model" + "github.com/TBD54566975/ftl/internal/rpc" "github.com/TBD54566975/ftl/internal/schema" "github.com/TBD54566975/ftl/internal/sha256" ) func TestDAL(t *testing.T) { ctx := log.ContextWithNewDefaultLogger(context.Background()) + timelineClient := timelinev1connect.NewTimelineServiceClient(http.DefaultClient, "http://localhost:8080") + ctx = rpc.ContextWithClient(ctx, timelineClient) conn := sqltest.OpenForTesting(ctx, t) encryption, err := encryption.New(ctx, conn, encryption.NewBuilder()) assert.NoError(t, err) - timelineSrv := timeline.New(ctx, conn, encryption) - pubSub := pubsub.New(ctx, conn, encryption, optional.None[pubsub.AsyncCallListener](), timelineSrv) + pubSub := pubsub.New(ctx, conn, encryption, optional.None[pubsub.AsyncCallListener]()) dal := New(ctx, conn, encryption, pubSub, artefacts.NewForTesting()) var testContent = bytes.Repeat([]byte("sometestcontentthatislongerthanthereadbuffer"), 100) @@ -191,8 +194,7 @@ func TestCreateArtefactConflict(t *testing.T) { encryption, err := encryption.New(ctx, conn, encryption.NewBuilder()) assert.NoError(t, err) - timelineSrv := timeline.New(ctx, conn, encryption) - pubSub := pubsub.New(ctx, conn, encryption, optional.None[pubsub.AsyncCallListener](), timelineSrv) + pubSub := pubsub.New(ctx, conn, encryption, optional.None[pubsub.AsyncCallListener]()) dal := New(ctx, conn, encryption, pubSub, artefacts.NewForTesting()) diff --git a/backend/controller/dal/internal/sql/deployment_queries.sql.go b/backend/controller/dal/internal/sql/deployment_queries.sql.go deleted file mode 100644 index 34a7b55897..0000000000 --- a/backend/controller/dal/internal/sql/deployment_queries.sql.go +++ /dev/null @@ -1,89 +0,0 @@ -// Code generated by sqlc. DO NOT EDIT. -// versions: -// sqlc v1.27.0 -// source: deployment_queries.sql - -package sql - -import ( - "context" - - "github.com/TBD54566975/ftl/backend/controller/encryption/api" - "github.com/TBD54566975/ftl/internal/model" -) - -const insertTimelineDeploymentCreatedEvent = `-- name: InsertTimelineDeploymentCreatedEvent :exec -INSERT INTO timeline ( - deployment_id, - type, - custom_key_1, - custom_key_2, - payload -) -VALUES ( - ( - SELECT id - FROM deployments - WHERE deployments.key = $1::deployment_key - ), - 'deployment_created', - $2::TEXT, - $3::TEXT, - $4 -) -` - -type InsertTimelineDeploymentCreatedEventParams struct { - DeploymentKey model.DeploymentKey - Language string - ModuleName string - Payload api.EncryptedTimelineColumn -} - -func (q *Queries) InsertTimelineDeploymentCreatedEvent(ctx context.Context, arg InsertTimelineDeploymentCreatedEventParams) error { - _, err := q.db.ExecContext(ctx, insertTimelineDeploymentCreatedEvent, - arg.DeploymentKey, - arg.Language, - arg.ModuleName, - arg.Payload, - ) - return err -} - -const insertTimelineDeploymentUpdatedEvent = `-- name: InsertTimelineDeploymentUpdatedEvent :exec -INSERT INTO timeline ( - deployment_id, - type, - custom_key_1, - custom_key_2, - payload -) -VALUES ( - ( - SELECT id - FROM deployments - WHERE deployments.key = $1::deployment_key - ), - 'deployment_updated', - $2::TEXT, - $3::TEXT, - $4 -) -` - -type InsertTimelineDeploymentUpdatedEventParams struct { - DeploymentKey model.DeploymentKey - Language string - ModuleName string - Payload api.EncryptedTimelineColumn -} - -func (q *Queries) InsertTimelineDeploymentUpdatedEvent(ctx context.Context, arg InsertTimelineDeploymentUpdatedEventParams) error { - _, err := q.db.ExecContext(ctx, insertTimelineDeploymentUpdatedEvent, - arg.DeploymentKey, - arg.Language, - arg.ModuleName, - arg.Payload, - ) - return err -} diff --git a/backend/controller/dal/internal/sql/querier.go b/backend/controller/dal/internal/sql/querier.go index 0dc480e6f6..0f7a328687 100644 --- a/backend/controller/dal/internal/sql/querier.go +++ b/backend/controller/dal/internal/sql/querier.go @@ -60,8 +60,6 @@ type Querier interface { GetTopicEvent(ctx context.Context, dollar_1 int64) (TopicEvent, error) GetZombieAsyncCalls(ctx context.Context, limit int32) ([]AsyncCall, error) InsertSubscriber(ctx context.Context, arg InsertSubscriberParams) error - InsertTimelineDeploymentCreatedEvent(ctx context.Context, arg InsertTimelineDeploymentCreatedEventParams) error - InsertTimelineDeploymentUpdatedEvent(ctx context.Context, arg InsertTimelineDeploymentUpdatedEventParams) error KillStaleRunners(ctx context.Context, timeout sqltypes.Duration) (int64, error) LoadAsyncCall(ctx context.Context, id int64) (AsyncCall, error) PublishEventForTopic(ctx context.Context, arg PublishEventForTopicParams) error diff --git a/backend/controller/deployment_logs.go b/backend/controller/deployment_logs.go index 48a90b1ce9..d79a8b532e 100644 --- a/backend/controller/deployment_logs.go +++ b/backend/controller/deployment_logs.go @@ -7,17 +7,16 @@ import ( "github.com/alecthomas/types/optional" - "github.com/TBD54566975/ftl/backend/controller/timeline" + "github.com/TBD54566975/ftl/backend/timeline" "github.com/TBD54566975/ftl/internal/log" "github.com/TBD54566975/ftl/internal/model" ) var _ log.Sink = (*deploymentLogsSink)(nil) -func newDeploymentLogsSink(ctx context.Context, timeline *timeline.Service) *deploymentLogsSink { +func newDeploymentLogsSink(ctx context.Context) *deploymentLogsSink { sink := &deploymentLogsSink{ logQueue: make(chan log.Entry, 10000), - timeline: timeline, } // Process logs in background @@ -28,7 +27,6 @@ func newDeploymentLogsSink(ctx context.Context, timeline *timeline.Service) *dep type deploymentLogsSink struct { logQueue chan log.Entry - timeline *timeline.Service } // Log implements Sink @@ -71,7 +69,7 @@ func (d *deploymentLogsSink) processLogs(ctx context.Context) { errorStr = optional.Some(entry.Error.Error()) } - d.timeline.EnqueueEvent(ctx, &timeline.Log{ + timeline.Publish(ctx, &timeline.Log{ RequestKey: request, DeploymentKey: deployment, Time: entry.Time, diff --git a/backend/controller/pubsub/internal/dal/dal.go b/backend/controller/pubsub/internal/dal/dal.go index 7af65aecfe..e4d530f250 100644 --- a/backend/controller/pubsub/internal/dal/dal.go +++ b/backend/controller/pubsub/internal/dal/dal.go @@ -14,8 +14,8 @@ import ( "github.com/TBD54566975/ftl/backend/controller/observability" dalsql "github.com/TBD54566975/ftl/backend/controller/pubsub/internal/sql" "github.com/TBD54566975/ftl/backend/controller/sql/sqltypes" - "github.com/TBD54566975/ftl/backend/controller/timeline" "github.com/TBD54566975/ftl/backend/libdal" + "github.com/TBD54566975/ftl/backend/timeline" "github.com/TBD54566975/ftl/internal/log" "github.com/TBD54566975/ftl/internal/model" "github.com/TBD54566975/ftl/internal/rpc" @@ -98,7 +98,7 @@ func (d *DAL) GetSubscriptionsNeedingUpdate(ctx context.Context) ([]model.Subscr }), nil } -func (d *DAL) ProgressSubscriptions(ctx context.Context, eventConsumptionDelay time.Duration, timelineSvc *timeline.Service) (count int, err error) { +func (d *DAL) ProgressSubscriptions(ctx context.Context, eventConsumptionDelay time.Duration) (count int, err error) { tx, err := d.Begin(ctx) if err != nil { return 0, fmt.Errorf("failed to begin transaction: %w", err) @@ -118,7 +118,7 @@ func (d *DAL) ProgressSubscriptions(ctx context.Context, eventConsumptionDelay t for _, subscription := range subs { now := time.Now().UTC() enqueueTimelineEvent := func(destVerb optional.Option[schema.RefKey], err optional.Option[string]) { - timelineSvc.EnqueueEvent(ctx, &timeline.PubSubConsume{ + timeline.Publish(ctx, &timeline.PubSubConsume{ DeploymentKey: subscription.DeploymentKey, RequestKey: subscription.RequestKey, Time: now, diff --git a/backend/controller/pubsub/service.go b/backend/controller/pubsub/service.go index 8e98b4f1a4..66b9202fc9 100644 --- a/backend/controller/pubsub/service.go +++ b/backend/controller/pubsub/service.go @@ -13,7 +13,6 @@ import ( "github.com/TBD54566975/ftl/backend/controller/encryption" "github.com/TBD54566975/ftl/backend/controller/pubsub/internal/dal" "github.com/TBD54566975/ftl/backend/controller/scheduledtask" - "github.com/TBD54566975/ftl/backend/controller/timeline" "github.com/TBD54566975/ftl/backend/libdal" "github.com/TBD54566975/ftl/internal/log" "github.com/TBD54566975/ftl/internal/model" @@ -40,15 +39,13 @@ type Service struct { dal *dal.DAL asyncCallListener optional.Option[AsyncCallListener] eventPublished chan struct{} - timelineSvc *timeline.Service } -func New(ctx context.Context, conn libdal.Connection, encryption *encryption.Service, asyncCallListener optional.Option[AsyncCallListener], timeline *timeline.Service) *Service { +func New(ctx context.Context, conn libdal.Connection, encryption *encryption.Service, asyncCallListener optional.Option[AsyncCallListener]) *Service { m := &Service{ dal: dal.New(conn, encryption), asyncCallListener: asyncCallListener, eventPublished: make(chan struct{}), - timelineSvc: timeline, } go m.poll(ctx) return m @@ -93,7 +90,7 @@ func (s *Service) poll(ctx context.Context) { } func (s *Service) progressSubscriptions(ctx context.Context) error { - count, err := s.dal.ProgressSubscriptions(ctx, eventConsumptionDelay, s.timelineSvc) + count, err := s.dal.ProgressSubscriptions(ctx, eventConsumptionDelay) if err != nil { return fmt.Errorf("progress subscriptions: %w", err) } diff --git a/backend/controller/timeline/events_async.go b/backend/controller/timeline/events_async.go index def3696ddc..698438aaf6 100644 --- a/backend/controller/timeline/events_async.go +++ b/backend/controller/timeline/events_async.go @@ -1,16 +1,10 @@ package timeline import ( - "context" - "encoding/json" - "fmt" "time" "github.com/alecthomas/types/optional" - ftlencryption "github.com/TBD54566975/ftl/backend/controller/encryption/api" - "github.com/TBD54566975/ftl/backend/controller/timeline/internal/sql" - "github.com/TBD54566975/ftl/backend/libdal" "github.com/TBD54566975/ftl/internal/model" "github.com/TBD54566975/ftl/internal/schema" ) @@ -53,35 +47,3 @@ type eventAsyncExecuteJSON struct { EventType AsyncExecuteEventType `json:"event_type"` Error optional.Option[string] `json:"error,omitempty"` } - -func (s *Service) insertAsyncExecuteEvent(ctx context.Context, querier sql.Querier, event *AsyncExecuteEvent) error { - asyncJSON := eventAsyncExecuteJSON{ - DurationMS: event.Duration.Milliseconds(), - EventType: event.EventType, - Error: event.Error, - } - - data, err := json.Marshal(asyncJSON) - if err != nil { - return fmt.Errorf("failed to marshal async execute event: %w", err) - } - - var payload ftlencryption.EncryptedTimelineColumn - err = s.encryption.EncryptJSON(json.RawMessage(data), &payload) - if err != nil { - return fmt.Errorf("failed to encrypt cron JSON: %w", err) - } - - err = libdal.TranslatePGError(querier.InsertTimelineAsyncExecuteEvent(ctx, sql.InsertTimelineAsyncExecuteEventParams{ - DeploymentKey: event.DeploymentKey, - RequestKey: event.RequestKey, - TimeStamp: event.Time, - Module: event.Verb.Module, - Verb: event.Verb.Name, - Payload: payload, - })) - if err != nil { - return fmt.Errorf("failed to insert async execute event: %w", err) - } - return err -} diff --git a/backend/controller/timeline/events_call.go b/backend/controller/timeline/events_call.go index b470eea0b2..9fe5095994 100644 --- a/backend/controller/timeline/events_call.go +++ b/backend/controller/timeline/events_call.go @@ -1,18 +1,13 @@ package timeline import ( - "context" "encoding/json" "errors" - "fmt" "time" "github.com/alecthomas/types/either" "github.com/alecthomas/types/optional" - ftlencryption "github.com/TBD54566975/ftl/backend/controller/encryption/api" - "github.com/TBD54566975/ftl/backend/controller/timeline/internal/sql" - "github.com/TBD54566975/ftl/backend/libdal" ftlv1 "github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/v1" "github.com/TBD54566975/ftl/internal/model" "github.com/TBD54566975/ftl/internal/schema" @@ -57,58 +52,6 @@ type Call struct { func (c *Call) toEvent() (Event, error) { return callToCallEvent(c), nil } //nolint:unparam -func (s *Service) insertCallEvent(ctx context.Context, querier sql.Querier, callEvent *CallEvent) error { - var sourceModule, sourceVerb optional.Option[string] - if sr, ok := callEvent.SourceVerb.Get(); ok { - sourceModule, sourceVerb = optional.Some(sr.Module), optional.Some(sr.Name) - } - - var requestKey optional.Option[string] - if rn, ok := callEvent.RequestKey.Get(); ok { - requestKey = optional.Some(rn.String()) - } - - var parentRequestKey optional.Option[string] - if pr, ok := callEvent.ParentRequestKey.Get(); ok { - parentRequestKey = optional.Some(pr.String()) - } - - callJSON := eventCallJSON{ - DurationMS: callEvent.Duration.Milliseconds(), - Request: callEvent.Request, - Response: callEvent.Response, - Error: callEvent.Error, - Stack: callEvent.Stack, - } - - data, err := json.Marshal(callJSON) - if err != nil { - return fmt.Errorf("failed to marshal call event: %w", err) - } - - var payload ftlencryption.EncryptedTimelineColumn - err = s.encryption.EncryptJSON(json.RawMessage(data), &payload) - if err != nil { - return fmt.Errorf("failed to encrypt call event: %w", err) - } - - err = libdal.TranslatePGError(querier.InsertTimelineCallEvent(ctx, sql.InsertTimelineCallEventParams{ - DeploymentKey: callEvent.DeploymentKey, - RequestKey: requestKey, - ParentRequestKey: parentRequestKey, - TimeStamp: callEvent.Time, - SourceModule: sourceModule, - SourceVerb: sourceVerb, - DestModule: callEvent.DestVerb.Module, - DestVerb: callEvent.DestVerb.Name, - Payload: payload, - })) - if err != nil { - return fmt.Errorf("failed to insert call event: %w", err) - } - return nil -} - func callToCallEvent(call *Call) *CallEvent { var sourceVerb optional.Option[schema.Ref] if len(call.Callers) > 0 { diff --git a/backend/controller/timeline/events_cron.go b/backend/controller/timeline/events_cron.go index 40394a3b2d..c0ba05293d 100644 --- a/backend/controller/timeline/events_cron.go +++ b/backend/controller/timeline/events_cron.go @@ -1,16 +1,10 @@ package timeline import ( - "context" - "encoding/json" - "fmt" "time" "github.com/alecthomas/types/optional" - ftlencryption "github.com/TBD54566975/ftl/backend/controller/encryption/api" - "github.com/TBD54566975/ftl/backend/controller/timeline/internal/sql" - "github.com/TBD54566975/ftl/backend/libdal" "github.com/TBD54566975/ftl/internal/model" "github.com/TBD54566975/ftl/internal/schema" ) @@ -47,35 +41,3 @@ type eventCronScheduledJSON struct { Schedule string `json:"schedule"` Error optional.Option[string] `json:"error,omitempty"` } - -func (s *Service) insertCronScheduledEvent(ctx context.Context, querier sql.Querier, event *CronScheduledEvent) error { - cronJSON := eventCronScheduledJSON{ - DurationMS: event.Duration.Milliseconds(), - ScheduledAt: event.ScheduledAt, - Schedule: event.Schedule, - Error: event.Error, - } - - data, err := json.Marshal(cronJSON) - if err != nil { - return fmt.Errorf("failed to marshal cron JSON: %w", err) - } - - var payload ftlencryption.EncryptedTimelineColumn - err = s.encryption.EncryptJSON(json.RawMessage(data), &payload) - if err != nil { - return fmt.Errorf("failed to encrypt cron JSON: %w", err) - } - - err = libdal.TranslatePGError(querier.InsertTimelineCronScheduledEvent(ctx, sql.InsertTimelineCronScheduledEventParams{ - DeploymentKey: event.DeploymentKey, - TimeStamp: event.Time, - Module: event.Verb.Module, - Verb: event.Verb.Name, - Payload: payload, - })) - if err != nil { - return fmt.Errorf("failed to insert cron event: %w", err) - } - return err -} diff --git a/backend/controller/timeline/events_ingress.go b/backend/controller/timeline/events_ingress.go index 325b4684fb..313c43b4a3 100644 --- a/backend/controller/timeline/events_ingress.go +++ b/backend/controller/timeline/events_ingress.go @@ -1,7 +1,6 @@ package timeline import ( - "context" "encoding/json" "fmt" "net/http" @@ -9,10 +8,6 @@ import ( "github.com/alecthomas/types/optional" - ftlencryption "github.com/TBD54566975/ftl/backend/controller/encryption/api" - "github.com/TBD54566975/ftl/backend/controller/timeline/internal/sql" - "github.com/TBD54566975/ftl/backend/libdal" - "github.com/TBD54566975/ftl/internal/log" "github.com/TBD54566975/ftl/internal/model" "github.com/TBD54566975/ftl/internal/schema" ) @@ -101,44 +96,3 @@ func (ingress *Ingress) toEvent() (Event, error) { Error: ingress.Error, }, nil } - -func (s *Service) insertHTTPIngress(ctx context.Context, querier sql.Querier, ingress *IngressEvent) error { - ingressJSON := eventIngressJSON{ - DurationMS: ingress.Duration.Milliseconds(), - Method: ingress.Method, - Path: ingress.Path, - StatusCode: ingress.StatusCode, - Request: ingress.Request, - RequestHeader: ingress.RequestHeader, - Response: ingress.Response, - ResponseHeader: ingress.ResponseHeader, - Error: ingress.Error, - } - - data, err := json.Marshal(ingressJSON) - if err != nil { - return fmt.Errorf("failed to marshal ingress JSON: %w", err) - } - - var payload ftlencryption.EncryptedTimelineColumn - err = s.encryption.EncryptJSON(json.RawMessage(data), &payload) - if err != nil { - return fmt.Errorf("failed to encrypt ingress payload: %w", err) - } - - log.FromContext(ctx).Debugf("Inserting ingress event for %s %s", ingress.RequestKey, ingress.Path) - - err = libdal.TranslatePGError(querier.InsertTimelineIngressEvent(ctx, sql.InsertTimelineIngressEventParams{ - DeploymentKey: ingress.DeploymentKey, - RequestKey: optional.Some(ingress.RequestKey.String()), - TimeStamp: ingress.Time, - Module: ingress.Verb.Module, - Verb: ingress.Verb.Name, - IngressType: "http", - Payload: payload, - })) - if err != nil { - return fmt.Errorf("failed to insert ingress event: %w", err) - } - return nil -} diff --git a/backend/controller/timeline/events_log.go b/backend/controller/timeline/events_log.go index 67952382b1..c6b8496f7a 100644 --- a/backend/controller/timeline/events_log.go +++ b/backend/controller/timeline/events_log.go @@ -1,16 +1,10 @@ package timeline import ( - "context" - "encoding/json" - "fmt" "time" "github.com/alecthomas/types/optional" - ftlencryption "github.com/TBD54566975/ftl/backend/controller/encryption/api" - "github.com/TBD54566975/ftl/backend/controller/timeline/internal/sql" - "github.com/TBD54566975/ftl/backend/libdal" "github.com/TBD54566975/ftl/internal/model" ) @@ -39,35 +33,3 @@ type eventLogJSON struct { Attributes map[string]string `json:"attributes"` Error optional.Option[string] `json:"error,omitempty"` } - -func (s *Service) insertLogEvent(ctx context.Context, querier sql.Querier, log *LogEvent) error { - var requestKey optional.Option[string] - if name, ok := log.RequestKey.Get(); ok { - requestKey = optional.Some(name.String()) - } - - logJSON := eventLogJSON{ - Message: log.Message, - Attributes: log.Attributes, - Error: log.Error, - } - - data, err := json.Marshal(logJSON) - if err != nil { - return fmt.Errorf("failed to marshal log event: %w", err) - } - - var encryptedPayload ftlencryption.EncryptedTimelineColumn - err = s.encryption.EncryptJSON(json.RawMessage(data), &encryptedPayload) - if err != nil { - return fmt.Errorf("failed to encrypt log payload: %w", err) - } - - return libdal.TranslatePGError(querier.InsertTimelineLogEvent(ctx, sql.InsertTimelineLogEventParams{ - DeploymentKey: log.DeploymentKey, - RequestKey: requestKey, - TimeStamp: log.Time, - Level: log.Level, - Payload: encryptedPayload, - })) -} diff --git a/backend/controller/timeline/events_pubsub_consume.go b/backend/controller/timeline/events_pubsub_consume.go index 66904dfae0..005e65a04c 100644 --- a/backend/controller/timeline/events_pubsub_consume.go +++ b/backend/controller/timeline/events_pubsub_consume.go @@ -1,16 +1,10 @@ package timeline import ( - "context" - "encoding/json" - "fmt" "time" "github.com/alecthomas/types/optional" - ftlencryption "github.com/TBD54566975/ftl/backend/controller/encryption/api" - "github.com/TBD54566975/ftl/backend/controller/timeline/internal/sql" - "github.com/TBD54566975/ftl/backend/libdal" "github.com/TBD54566975/ftl/internal/model" "github.com/TBD54566975/ftl/internal/schema" ) @@ -45,43 +39,3 @@ type eventPubSubConsumeJSON struct { Topic string `json:"topic"` Error optional.Option[string] `json:"error,omitempty"` } - -func (s *Service) insertPubSubConsumeEvent(ctx context.Context, querier sql.Querier, event *PubSubConsumeEvent) error { - pubsubJSON := eventPubSubConsumeJSON{ - DurationMS: event.Duration.Milliseconds(), - Topic: event.Topic, - Error: event.Error, - } - - data, err := json.Marshal(pubsubJSON) - if err != nil { - return fmt.Errorf("failed to marshal pubsub event: %w", err) - } - - var payload ftlencryption.EncryptedTimelineColumn - err = s.encryption.EncryptJSON(json.RawMessage(data), &payload) - if err != nil { - return fmt.Errorf("failed to encrypt cron JSON: %w", err) - } - - destModule := optional.None[string]() - destVerb := optional.None[string]() - if dv, ok := event.DestVerb.Get(); ok { - destModule = optional.Some(dv.Module) - destVerb = optional.Some(dv.Name) - } - - err = libdal.TranslatePGError(querier.InsertTimelinePubsubConsumeEvent(ctx, sql.InsertTimelinePubsubConsumeEventParams{ - DeploymentKey: event.DeploymentKey, - RequestKey: event.RequestKey, - TimeStamp: event.Time, - DestModule: destModule, - DestVerb: destVerb, - Topic: event.Topic, - Payload: payload, - })) - if err != nil { - return fmt.Errorf("failed to insert pubsub consume event: %w", err) - } - return err -} diff --git a/backend/controller/timeline/events_pubsub_publish.go b/backend/controller/timeline/events_pubsub_publish.go index b3d2b072af..ff44560bbd 100644 --- a/backend/controller/timeline/events_pubsub_publish.go +++ b/backend/controller/timeline/events_pubsub_publish.go @@ -1,16 +1,11 @@ package timeline import ( - "context" "encoding/json" - "fmt" "time" "github.com/alecthomas/types/optional" - ftlencryption "github.com/TBD54566975/ftl/backend/controller/encryption/api" - "github.com/TBD54566975/ftl/backend/controller/timeline/internal/sql" - "github.com/TBD54566975/ftl/backend/libdal" deployment "github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/deployment/v1" "github.com/TBD54566975/ftl/internal/model" "github.com/TBD54566975/ftl/internal/schema" @@ -49,37 +44,3 @@ type eventPubSubPublishJSON struct { Request json.RawMessage `json:"request"` Error optional.Option[string] `json:"error,omitempty"` } - -func (s *Service) insertPubSubPublishEvent(ctx context.Context, querier sql.Querier, event *PubSubPublishEvent) error { - pubsubJSON := eventPubSubPublishJSON{ - DurationMS: event.Duration.Milliseconds(), - Topic: event.Topic, - Request: event.Request, - Error: event.Error, - } - - data, err := json.Marshal(pubsubJSON) - if err != nil { - return fmt.Errorf("failed to marshal pubsub event: %w", err) - } - - var payload ftlencryption.EncryptedTimelineColumn - err = s.encryption.EncryptJSON(json.RawMessage(data), &payload) - if err != nil { - return fmt.Errorf("failed to encrypt cron JSON: %w", err) - } - - err = libdal.TranslatePGError(querier.InsertTimelinePubsubPublishEvent(ctx, sql.InsertTimelinePubsubPublishEventParams{ - DeploymentKey: event.DeploymentKey, - RequestKey: event.RequestKey, - TimeStamp: event.Time, - SourceModule: event.SourceVerb.Module, - SourceVerb: event.SourceVerb.Name, - Topic: event.Topic, - Payload: payload, - })) - if err != nil { - return fmt.Errorf("failed to insert pubsub publish event: %w", err) - } - return err -} diff --git a/backend/controller/timeline/internal/sql/db.go b/backend/controller/timeline/internal/sql/db.go deleted file mode 100644 index 0e0973111c..0000000000 --- a/backend/controller/timeline/internal/sql/db.go +++ /dev/null @@ -1,31 +0,0 @@ -// Code generated by sqlc. DO NOT EDIT. -// versions: -// sqlc v1.27.0 - -package sql - -import ( - "context" - "database/sql" -) - -type DBTX interface { - ExecContext(context.Context, string, ...interface{}) (sql.Result, error) - PrepareContext(context.Context, string) (*sql.Stmt, error) - QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) - QueryRowContext(context.Context, string, ...interface{}) *sql.Row -} - -func New(db DBTX) *Queries { - return &Queries{db: db} -} - -type Queries struct { - db DBTX -} - -func (q *Queries) WithTx(tx *sql.Tx) *Queries { - return &Queries{ - db: tx, - } -} diff --git a/backend/controller/timeline/internal/sql/deployment_queries.sql b/backend/controller/timeline/internal/sql/deployment_queries.sql deleted file mode 100644 index 268a22047e..0000000000 --- a/backend/controller/timeline/internal/sql/deployment_queries.sql +++ /dev/null @@ -1,39 +0,0 @@ --- name: InsertTimelineDeploymentCreatedEvent :exec -INSERT INTO timeline ( - deployment_id, - type, - custom_key_1, - custom_key_2, - payload -) -VALUES ( - ( - SELECT id - FROM deployments - WHERE deployments.key = sqlc.arg('deployment_key')::deployment_key - ), - 'deployment_created', - sqlc.arg('language')::TEXT, - sqlc.arg('module_name')::TEXT, - sqlc.arg('payload') -); - --- name: InsertTimelineDeploymentUpdatedEvent :exec -INSERT INTO timeline ( - deployment_id, - type, - custom_key_1, - custom_key_2, - payload -) -VALUES ( - ( - SELECT id - FROM deployments - WHERE deployments.key = sqlc.arg('deployment_key')::deployment_key - ), - 'deployment_updated', - sqlc.arg('language')::TEXT, - sqlc.arg('module_name')::TEXT, - sqlc.arg('payload') -); diff --git a/backend/controller/timeline/internal/sql/deployment_queries.sql.go b/backend/controller/timeline/internal/sql/deployment_queries.sql.go deleted file mode 100644 index 34a7b55897..0000000000 --- a/backend/controller/timeline/internal/sql/deployment_queries.sql.go +++ /dev/null @@ -1,89 +0,0 @@ -// Code generated by sqlc. DO NOT EDIT. -// versions: -// sqlc v1.27.0 -// source: deployment_queries.sql - -package sql - -import ( - "context" - - "github.com/TBD54566975/ftl/backend/controller/encryption/api" - "github.com/TBD54566975/ftl/internal/model" -) - -const insertTimelineDeploymentCreatedEvent = `-- name: InsertTimelineDeploymentCreatedEvent :exec -INSERT INTO timeline ( - deployment_id, - type, - custom_key_1, - custom_key_2, - payload -) -VALUES ( - ( - SELECT id - FROM deployments - WHERE deployments.key = $1::deployment_key - ), - 'deployment_created', - $2::TEXT, - $3::TEXT, - $4 -) -` - -type InsertTimelineDeploymentCreatedEventParams struct { - DeploymentKey model.DeploymentKey - Language string - ModuleName string - Payload api.EncryptedTimelineColumn -} - -func (q *Queries) InsertTimelineDeploymentCreatedEvent(ctx context.Context, arg InsertTimelineDeploymentCreatedEventParams) error { - _, err := q.db.ExecContext(ctx, insertTimelineDeploymentCreatedEvent, - arg.DeploymentKey, - arg.Language, - arg.ModuleName, - arg.Payload, - ) - return err -} - -const insertTimelineDeploymentUpdatedEvent = `-- name: InsertTimelineDeploymentUpdatedEvent :exec -INSERT INTO timeline ( - deployment_id, - type, - custom_key_1, - custom_key_2, - payload -) -VALUES ( - ( - SELECT id - FROM deployments - WHERE deployments.key = $1::deployment_key - ), - 'deployment_updated', - $2::TEXT, - $3::TEXT, - $4 -) -` - -type InsertTimelineDeploymentUpdatedEventParams struct { - DeploymentKey model.DeploymentKey - Language string - ModuleName string - Payload api.EncryptedTimelineColumn -} - -func (q *Queries) InsertTimelineDeploymentUpdatedEvent(ctx context.Context, arg InsertTimelineDeploymentUpdatedEventParams) error { - _, err := q.db.ExecContext(ctx, insertTimelineDeploymentUpdatedEvent, - arg.DeploymentKey, - arg.Language, - arg.ModuleName, - arg.Payload, - ) - return err -} diff --git a/backend/controller/timeline/internal/sql/querier.go b/backend/controller/timeline/internal/sql/querier.go deleted file mode 100644 index ad15ffef67..0000000000 --- a/backend/controller/timeline/internal/sql/querier.go +++ /dev/null @@ -1,28 +0,0 @@ -// Code generated by sqlc. DO NOT EDIT. -// versions: -// sqlc v1.27.0 - -package sql - -import ( - "context" - - "github.com/TBD54566975/ftl/backend/controller/sql/sqltypes" -) - -type Querier interface { - DeleteOldTimelineEvents(ctx context.Context, timeout sqltypes.Duration, type_ EventType) (int64, error) - // This is a dummy query to ensure that the Timeline model is generated. - DummyQueryTimeline(ctx context.Context, id int64) (Timeline, error) - InsertTimelineAsyncExecuteEvent(ctx context.Context, arg InsertTimelineAsyncExecuteEventParams) error - InsertTimelineCallEvent(ctx context.Context, arg InsertTimelineCallEventParams) error - InsertTimelineCronScheduledEvent(ctx context.Context, arg InsertTimelineCronScheduledEventParams) error - InsertTimelineDeploymentCreatedEvent(ctx context.Context, arg InsertTimelineDeploymentCreatedEventParams) error - InsertTimelineDeploymentUpdatedEvent(ctx context.Context, arg InsertTimelineDeploymentUpdatedEventParams) error - InsertTimelineIngressEvent(ctx context.Context, arg InsertTimelineIngressEventParams) error - InsertTimelineLogEvent(ctx context.Context, arg InsertTimelineLogEventParams) error - InsertTimelinePubsubConsumeEvent(ctx context.Context, arg InsertTimelinePubsubConsumeEventParams) error - InsertTimelinePubsubPublishEvent(ctx context.Context, arg InsertTimelinePubsubPublishEventParams) error -} - -var _ Querier = (*Queries)(nil) diff --git a/backend/controller/timeline/internal/sql/queries.sql b/backend/controller/timeline/internal/sql/queries.sql deleted file mode 100644 index 2eee3cdfdf..0000000000 --- a/backend/controller/timeline/internal/sql/queries.sql +++ /dev/null @@ -1,186 +0,0 @@ --- name: InsertTimelineLogEvent :exec -INSERT INTO timeline ( - deployment_id, - request_id, - time_stamp, - custom_key_1, - type, - payload -) -VALUES ( - (SELECT id FROM deployments d WHERE d.key = sqlc.arg('deployment_key')::deployment_key LIMIT 1), - ( - CASE - WHEN sqlc.narg('request_key')::TEXT IS NULL THEN NULL - ELSE (SELECT id FROM requests ir WHERE ir.key = sqlc.narg('request_key')::TEXT LIMIT 1) - END - ), - sqlc.arg('time_stamp')::TIMESTAMPTZ, - sqlc.arg('level')::INT, - 'log', - sqlc.arg('payload') -); - --- name: InsertTimelineCallEvent :exec -INSERT INTO timeline ( - deployment_id, - request_id, - parent_request_id, - time_stamp, - type, - custom_key_1, - custom_key_2, - custom_key_3, - custom_key_4, - payload -) -VALUES ( - (SELECT id FROM deployments WHERE deployments.key = sqlc.arg('deployment_key')::deployment_key), - (CASE - WHEN sqlc.narg('request_key')::TEXT IS NULL THEN NULL - ELSE (SELECT id FROM requests ir WHERE ir.key = sqlc.narg('request_key')::TEXT) - END), - (CASE - WHEN sqlc.narg('parent_request_key')::TEXT IS NULL THEN NULL - ELSE (SELECT id FROM requests ir WHERE ir.key = sqlc.narg('parent_request_key')::TEXT) - END), - sqlc.arg('time_stamp')::TIMESTAMPTZ, - 'call', - sqlc.narg('source_module')::TEXT, - sqlc.narg('source_verb')::TEXT, - sqlc.arg('dest_module')::TEXT, - sqlc.arg('dest_verb')::TEXT, - sqlc.arg('payload') -); - --- name: InsertTimelineIngressEvent :exec -INSERT INTO timeline ( - deployment_id, - request_id, - time_stamp, - type, - custom_key_1, - custom_key_2, - custom_key_3, - payload -) -VALUES ( - (SELECT id FROM deployments d WHERE d.key = sqlc.arg('deployment_key')::deployment_key LIMIT 1), - ( - CASE - WHEN sqlc.narg('request_key')::TEXT IS NULL THEN NULL - ELSE (SELECT id FROM requests ir WHERE ir.key = sqlc.narg('request_key')::TEXT LIMIT 1) - END - ), - sqlc.arg('time_stamp')::TIMESTAMPTZ, - 'ingress', - sqlc.arg('module')::TEXT, - sqlc.arg('verb')::TEXT, - sqlc.arg('ingress_type')::TEXT, - sqlc.arg('payload') -); - --- name: InsertTimelineCronScheduledEvent :exec -INSERT INTO timeline ( - deployment_id, - time_stamp, - type, - custom_key_1, - custom_key_2, - payload -) -VALUES ( - (SELECT id FROM deployments d WHERE d.key = sqlc.arg('deployment_key')::deployment_key LIMIT 1), - sqlc.arg('time_stamp')::TIMESTAMPTZ, - 'cron_scheduled', - sqlc.arg('module')::TEXT, - sqlc.arg('verb')::TEXT, - sqlc.arg('payload') -); - --- name: InsertTimelineAsyncExecuteEvent :exec -INSERT INTO timeline ( - deployment_id, - request_id, - time_stamp, - type, - custom_key_1, - custom_key_2, - payload -) -VALUES ( - (SELECT id FROM deployments d WHERE d.key = sqlc.arg('deployment_key')::deployment_key LIMIT 1), - (CASE - WHEN sqlc.narg('request_key')::TEXT IS NULL THEN NULL - ELSE (SELECT id FROM requests ir WHERE ir.key = sqlc.narg('request_key')::TEXT) - END), - sqlc.arg('time_stamp')::TIMESTAMPTZ, - 'async_execute', - sqlc.arg('module')::TEXT, - sqlc.arg('verb')::TEXT, - sqlc.arg('payload') -); - --- name: InsertTimelinePubsubPublishEvent :exec -INSERT INTO timeline ( - deployment_id, - request_id, - time_stamp, - type, - custom_key_1, - custom_key_2, - custom_key_3, - payload -) -VALUES ( - (SELECT id FROM deployments d WHERE d.key = sqlc.arg('deployment_key')::deployment_key LIMIT 1), - (CASE - WHEN sqlc.narg('request_key')::TEXT IS NULL THEN NULL - ELSE (SELECT id FROM requests ir WHERE ir.key = sqlc.narg('request_key')::TEXT) - END), - sqlc.arg('time_stamp')::TIMESTAMPTZ, - 'pubsub_publish', - sqlc.arg('source_module')::TEXT, - sqlc.arg('source_verb')::TEXT, - sqlc.arg('topic')::TEXT, - sqlc.arg('payload') -); - --- name: InsertTimelinePubsubConsumeEvent :exec -INSERT INTO timeline ( - deployment_id, - request_id, - time_stamp, - type, - custom_key_1, - custom_key_2, - custom_key_3, - payload -) -VALUES ( - (SELECT id FROM deployments d WHERE d.key = sqlc.arg('deployment_key')::deployment_key LIMIT 1), - (CASE - WHEN sqlc.narg('request_key')::TEXT IS NULL THEN NULL - ELSE (SELECT id FROM requests ir WHERE ir.key = sqlc.narg('request_key')::TEXT) - END), - sqlc.arg('time_stamp')::TIMESTAMPTZ, - 'pubsub_consume', - sqlc.narg('dest_module')::TEXT, - sqlc.narg('dest_verb')::TEXT, - sqlc.arg('topic')::TEXT, - sqlc.arg('payload') -); - --- name: DeleteOldTimelineEvents :one -WITH deleted AS ( - DELETE FROM timeline - WHERE time_stamp < (NOW() AT TIME ZONE 'utc') - sqlc.arg('timeout')::INTERVAL - AND type = sqlc.arg('type') - RETURNING 1 -) -SELECT COUNT(*) -FROM deleted; - --- name: DummyQueryTimeline :one --- This is a dummy query to ensure that the Timeline model is generated. -SELECT * FROM timeline WHERE id = @id; diff --git a/backend/controller/timeline/internal/sql/queries.sql.go b/backend/controller/timeline/internal/sql/queries.sql.go deleted file mode 100644 index 6ea635a67f..0000000000 --- a/backend/controller/timeline/internal/sql/queries.sql.go +++ /dev/null @@ -1,393 +0,0 @@ -// Code generated by sqlc. DO NOT EDIT. -// versions: -// sqlc v1.27.0 -// source: queries.sql - -package sql - -import ( - "context" - "time" - - "github.com/TBD54566975/ftl/backend/controller/encryption/api" - "github.com/TBD54566975/ftl/backend/controller/sql/sqltypes" - "github.com/TBD54566975/ftl/internal/model" - "github.com/alecthomas/types/optional" -) - -const deleteOldTimelineEvents = `-- name: DeleteOldTimelineEvents :one -WITH deleted AS ( - DELETE FROM timeline - WHERE time_stamp < (NOW() AT TIME ZONE 'utc') - $1::INTERVAL - AND type = $2 - RETURNING 1 -) -SELECT COUNT(*) -FROM deleted -` - -func (q *Queries) DeleteOldTimelineEvents(ctx context.Context, timeout sqltypes.Duration, type_ EventType) (int64, error) { - row := q.db.QueryRowContext(ctx, deleteOldTimelineEvents, timeout, type_) - var count int64 - err := row.Scan(&count) - return count, err -} - -const dummyQueryTimeline = `-- name: DummyQueryTimeline :one -SELECT id, time_stamp, deployment_id, request_id, type, custom_key_1, custom_key_2, custom_key_3, custom_key_4, payload, parent_request_id FROM timeline WHERE id = $1 -` - -// This is a dummy query to ensure that the Timeline model is generated. -func (q *Queries) DummyQueryTimeline(ctx context.Context, id int64) (Timeline, error) { - row := q.db.QueryRowContext(ctx, dummyQueryTimeline, id) - var i Timeline - err := row.Scan( - &i.ID, - &i.TimeStamp, - &i.DeploymentID, - &i.RequestID, - &i.Type, - &i.CustomKey1, - &i.CustomKey2, - &i.CustomKey3, - &i.CustomKey4, - &i.Payload, - &i.ParentRequestID, - ) - return i, err -} - -const insertTimelineAsyncExecuteEvent = `-- name: InsertTimelineAsyncExecuteEvent :exec -INSERT INTO timeline ( - deployment_id, - request_id, - time_stamp, - type, - custom_key_1, - custom_key_2, - payload -) -VALUES ( - (SELECT id FROM deployments d WHERE d.key = $1::deployment_key LIMIT 1), - (CASE - WHEN $2::TEXT IS NULL THEN NULL - ELSE (SELECT id FROM requests ir WHERE ir.key = $2::TEXT) - END), - $3::TIMESTAMPTZ, - 'async_execute', - $4::TEXT, - $5::TEXT, - $6 -) -` - -type InsertTimelineAsyncExecuteEventParams struct { - DeploymentKey model.DeploymentKey - RequestKey optional.Option[string] - TimeStamp time.Time - Module string - Verb string - Payload api.EncryptedTimelineColumn -} - -func (q *Queries) InsertTimelineAsyncExecuteEvent(ctx context.Context, arg InsertTimelineAsyncExecuteEventParams) error { - _, err := q.db.ExecContext(ctx, insertTimelineAsyncExecuteEvent, - arg.DeploymentKey, - arg.RequestKey, - arg.TimeStamp, - arg.Module, - arg.Verb, - arg.Payload, - ) - return err -} - -const insertTimelineCallEvent = `-- name: InsertTimelineCallEvent :exec -INSERT INTO timeline ( - deployment_id, - request_id, - parent_request_id, - time_stamp, - type, - custom_key_1, - custom_key_2, - custom_key_3, - custom_key_4, - payload -) -VALUES ( - (SELECT id FROM deployments WHERE deployments.key = $1::deployment_key), - (CASE - WHEN $2::TEXT IS NULL THEN NULL - ELSE (SELECT id FROM requests ir WHERE ir.key = $2::TEXT) - END), - (CASE - WHEN $3::TEXT IS NULL THEN NULL - ELSE (SELECT id FROM requests ir WHERE ir.key = $3::TEXT) - END), - $4::TIMESTAMPTZ, - 'call', - $5::TEXT, - $6::TEXT, - $7::TEXT, - $8::TEXT, - $9 -) -` - -type InsertTimelineCallEventParams struct { - DeploymentKey model.DeploymentKey - RequestKey optional.Option[string] - ParentRequestKey optional.Option[string] - TimeStamp time.Time - SourceModule optional.Option[string] - SourceVerb optional.Option[string] - DestModule string - DestVerb string - Payload api.EncryptedTimelineColumn -} - -func (q *Queries) InsertTimelineCallEvent(ctx context.Context, arg InsertTimelineCallEventParams) error { - _, err := q.db.ExecContext(ctx, insertTimelineCallEvent, - arg.DeploymentKey, - arg.RequestKey, - arg.ParentRequestKey, - arg.TimeStamp, - arg.SourceModule, - arg.SourceVerb, - arg.DestModule, - arg.DestVerb, - arg.Payload, - ) - return err -} - -const insertTimelineCronScheduledEvent = `-- name: InsertTimelineCronScheduledEvent :exec -INSERT INTO timeline ( - deployment_id, - time_stamp, - type, - custom_key_1, - custom_key_2, - payload -) -VALUES ( - (SELECT id FROM deployments d WHERE d.key = $1::deployment_key LIMIT 1), - $2::TIMESTAMPTZ, - 'cron_scheduled', - $3::TEXT, - $4::TEXT, - $5 -) -` - -type InsertTimelineCronScheduledEventParams struct { - DeploymentKey model.DeploymentKey - TimeStamp time.Time - Module string - Verb string - Payload api.EncryptedTimelineColumn -} - -func (q *Queries) InsertTimelineCronScheduledEvent(ctx context.Context, arg InsertTimelineCronScheduledEventParams) error { - _, err := q.db.ExecContext(ctx, insertTimelineCronScheduledEvent, - arg.DeploymentKey, - arg.TimeStamp, - arg.Module, - arg.Verb, - arg.Payload, - ) - return err -} - -const insertTimelineIngressEvent = `-- name: InsertTimelineIngressEvent :exec -INSERT INTO timeline ( - deployment_id, - request_id, - time_stamp, - type, - custom_key_1, - custom_key_2, - custom_key_3, - payload -) -VALUES ( - (SELECT id FROM deployments d WHERE d.key = $1::deployment_key LIMIT 1), - ( - CASE - WHEN $2::TEXT IS NULL THEN NULL - ELSE (SELECT id FROM requests ir WHERE ir.key = $2::TEXT LIMIT 1) - END - ), - $3::TIMESTAMPTZ, - 'ingress', - $4::TEXT, - $5::TEXT, - $6::TEXT, - $7 -) -` - -type InsertTimelineIngressEventParams struct { - DeploymentKey model.DeploymentKey - RequestKey optional.Option[string] - TimeStamp time.Time - Module string - Verb string - IngressType string - Payload api.EncryptedTimelineColumn -} - -func (q *Queries) InsertTimelineIngressEvent(ctx context.Context, arg InsertTimelineIngressEventParams) error { - _, err := q.db.ExecContext(ctx, insertTimelineIngressEvent, - arg.DeploymentKey, - arg.RequestKey, - arg.TimeStamp, - arg.Module, - arg.Verb, - arg.IngressType, - arg.Payload, - ) - return err -} - -const insertTimelineLogEvent = `-- name: InsertTimelineLogEvent :exec -INSERT INTO timeline ( - deployment_id, - request_id, - time_stamp, - custom_key_1, - type, - payload -) -VALUES ( - (SELECT id FROM deployments d WHERE d.key = $1::deployment_key LIMIT 1), - ( - CASE - WHEN $2::TEXT IS NULL THEN NULL - ELSE (SELECT id FROM requests ir WHERE ir.key = $2::TEXT LIMIT 1) - END - ), - $3::TIMESTAMPTZ, - $4::INT, - 'log', - $5 -) -` - -type InsertTimelineLogEventParams struct { - DeploymentKey model.DeploymentKey - RequestKey optional.Option[string] - TimeStamp time.Time - Level int32 - Payload api.EncryptedTimelineColumn -} - -func (q *Queries) InsertTimelineLogEvent(ctx context.Context, arg InsertTimelineLogEventParams) error { - _, err := q.db.ExecContext(ctx, insertTimelineLogEvent, - arg.DeploymentKey, - arg.RequestKey, - arg.TimeStamp, - arg.Level, - arg.Payload, - ) - return err -} - -const insertTimelinePubsubConsumeEvent = `-- name: InsertTimelinePubsubConsumeEvent :exec -INSERT INTO timeline ( - deployment_id, - request_id, - time_stamp, - type, - custom_key_1, - custom_key_2, - custom_key_3, - payload -) -VALUES ( - (SELECT id FROM deployments d WHERE d.key = $1::deployment_key LIMIT 1), - (CASE - WHEN $2::TEXT IS NULL THEN NULL - ELSE (SELECT id FROM requests ir WHERE ir.key = $2::TEXT) - END), - $3::TIMESTAMPTZ, - 'pubsub_consume', - $4::TEXT, - $5::TEXT, - $6::TEXT, - $7 -) -` - -type InsertTimelinePubsubConsumeEventParams struct { - DeploymentKey model.DeploymentKey - RequestKey optional.Option[string] - TimeStamp time.Time - DestModule optional.Option[string] - DestVerb optional.Option[string] - Topic string - Payload api.EncryptedTimelineColumn -} - -func (q *Queries) InsertTimelinePubsubConsumeEvent(ctx context.Context, arg InsertTimelinePubsubConsumeEventParams) error { - _, err := q.db.ExecContext(ctx, insertTimelinePubsubConsumeEvent, - arg.DeploymentKey, - arg.RequestKey, - arg.TimeStamp, - arg.DestModule, - arg.DestVerb, - arg.Topic, - arg.Payload, - ) - return err -} - -const insertTimelinePubsubPublishEvent = `-- name: InsertTimelinePubsubPublishEvent :exec -INSERT INTO timeline ( - deployment_id, - request_id, - time_stamp, - type, - custom_key_1, - custom_key_2, - custom_key_3, - payload -) -VALUES ( - (SELECT id FROM deployments d WHERE d.key = $1::deployment_key LIMIT 1), - (CASE - WHEN $2::TEXT IS NULL THEN NULL - ELSE (SELECT id FROM requests ir WHERE ir.key = $2::TEXT) - END), - $3::TIMESTAMPTZ, - 'pubsub_publish', - $4::TEXT, - $5::TEXT, - $6::TEXT, - $7 -) -` - -type InsertTimelinePubsubPublishEventParams struct { - DeploymentKey model.DeploymentKey - RequestKey optional.Option[string] - TimeStamp time.Time - SourceModule string - SourceVerb string - Topic string - Payload api.EncryptedTimelineColumn -} - -func (q *Queries) InsertTimelinePubsubPublishEvent(ctx context.Context, arg InsertTimelinePubsubPublishEventParams) error { - _, err := q.db.ExecContext(ctx, insertTimelinePubsubPublishEvent, - arg.DeploymentKey, - arg.RequestKey, - arg.TimeStamp, - arg.SourceModule, - arg.SourceVerb, - arg.Topic, - arg.Payload, - ) - return err -} diff --git a/backend/controller/timeline/internal/timeline_test.go b/backend/controller/timeline/internal/timeline_test.go deleted file mode 100644 index b7eee0d379..0000000000 --- a/backend/controller/timeline/internal/timeline_test.go +++ /dev/null @@ -1,420 +0,0 @@ -package internal - -import ( - "bytes" - "context" - "encoding/json" - "net/http" - "reflect" - "testing" - "time" - - "github.com/alecthomas/assert/v2" - "github.com/alecthomas/types/optional" - - "github.com/TBD54566975/ftl/backend/controller/artefacts" - timeline2 "github.com/TBD54566975/ftl/backend/controller/timeline" - - controllerdal "github.com/TBD54566975/ftl/backend/controller/dal" - dalmodel "github.com/TBD54566975/ftl/backend/controller/dal/model" - "github.com/TBD54566975/ftl/backend/controller/encryption" - "github.com/TBD54566975/ftl/backend/controller/pubsub" - "github.com/TBD54566975/ftl/backend/controller/sql/sqltest" - "github.com/TBD54566975/ftl/internal/log" - "github.com/TBD54566975/ftl/internal/model" - "github.com/TBD54566975/ftl/internal/schema" - "github.com/TBD54566975/ftl/internal/sha256" -) - -func TestTimeline(t *testing.T) { - ctx := log.ContextWithNewDefaultLogger(context.Background()) - conn := sqltest.OpenForTesting(ctx, t) - encryption, err := encryption.New(ctx, conn, encryption.NewBuilder()) - assert.NoError(t, err) - - timeline := timeline2.New(ctx, conn, encryption) - pubSub := pubsub.New(ctx, conn, encryption, optional.None[pubsub.AsyncCallListener](), timeline) - - registry := artefacts.NewForTesting() - controllerDAL := controllerdal.New(ctx, conn, encryption, pubSub, registry) - - var testContent = bytes.Repeat([]byte("sometestcontentthatislongerthanthereadbuffer"), 100) - - t.Run("UpsertModule", func(t *testing.T) { - err = controllerDAL.UpsertModule(ctx, "go", "test") - assert.NoError(t, err) - }) - - var testSha sha256.SHA256 - - t.Run("CreateArtefact", func(t *testing.T) { - testSha, err = registry.Upload(ctx, artefacts.Artefact{Content: testContent}) - assert.NoError(t, err) - }) - - module := &schema.Module{Name: "test"} - var deploymentKey model.DeploymentKey - t.Run("CreateDeployment", func(t *testing.T) { - deploymentKey, err = controllerDAL.CreateDeployment(ctx, "go", module, []dalmodel.DeploymentArtefact{{ - Digest: testSha, - Executable: true, - Path: "dir/filename", - }}) - assert.NoError(t, err) - time.Sleep(200 * time.Millisecond) - }) - - t.Run("SetDeploymentReplicas", func(t *testing.T) { - err := controllerDAL.SetDeploymentReplicas(ctx, deploymentKey, 1) - assert.NoError(t, err) - }) - - requestKey := model.NewRequestKey(model.OriginIngress, "GET /test") - t.Run("CreateIngressRequest", func(t *testing.T) { - err = controllerDAL.CreateRequest(ctx, requestKey, "127.0.0.1:1234") - assert.NoError(t, err) - }) - - callEvent := &timeline2.CallEvent{ - Time: time.Now().Round(time.Millisecond), - DeploymentKey: deploymentKey, - RequestKey: optional.Some(requestKey), - Request: []byte("{}"), - Response: []byte(`{"time":"now"}`), - DestVerb: schema.Ref{Module: "time", Name: "time"}, - } - - t.Run("InsertCallEvent", func(t *testing.T) { - call := timeline2.CallEventToCallForTesting(callEvent) - timeline.EnqueueEvent(ctx, call) - time.Sleep(200 * time.Millisecond) - }) - - logEvent := &timeline2.LogEvent{ - Log: timeline2.Log{ - Time: time.Now().Round(time.Millisecond), - DeploymentKey: deploymentKey, - RequestKey: optional.Some(requestKey), - Level: int32(log.Warn), - Attributes: map[string]string{"attr": "value"}, - Message: "A log entry", - }, - } - t.Run("InsertLogEntry", func(t *testing.T) { - timeline.EnqueueEvent(ctx, &logEvent.Log) - time.Sleep(200 * time.Millisecond) - }) - - ingressEvent := &timeline2.IngressEvent{ - DeploymentKey: deploymentKey, - RequestKey: optional.Some(requestKey), - Verb: schema.Ref{Module: "time", Name: "time"}, - Method: "GET", - Path: "/time", - StatusCode: 200, - Time: time.Now().Round(time.Millisecond), - Request: []byte(`{"request":"body"}`), - RequestHeader: json.RawMessage(`{"request":["header"]}`), - Response: []byte(`{"response":"body"}`), - ResponseHeader: json.RawMessage(`{"response":["header"]}`), - } - - t.Run("InsertHTTPIngressEvent", func(t *testing.T) { - timeline.EnqueueEvent(ctx, &timeline2.Ingress{ - DeploymentKey: ingressEvent.DeploymentKey, - RequestKey: ingressEvent.RequestKey.MustGet(), - StartTime: ingressEvent.Time, - Verb: &ingressEvent.Verb, - RequestMethod: ingressEvent.Method, - RequestPath: ingressEvent.Path, - RequestHeaders: http.Header(map[string][]string{"request": {"header"}}), - RequestBody: ingressEvent.Request, - ResponseStatus: ingressEvent.StatusCode, - ResponseHeaders: http.Header(map[string][]string{"response": {"header"}}), - ResponseBody: ingressEvent.Response, - }) - time.Sleep(200 * time.Millisecond) - }) - - cronEvent := &timeline2.CronScheduledEvent{ - CronScheduled: timeline2.CronScheduled{ - DeploymentKey: deploymentKey, - Verb: schema.Ref{Module: "time", Name: "time"}, - Time: time.Now().Round(time.Millisecond), - ScheduledAt: time.Now().Add(time.Minute).Round(time.Millisecond).UTC(), - Schedule: "* * * * *", - Error: optional.None[string](), - }, - } - - t.Run("InsertCronScheduledEvent", func(t *testing.T) { - timeline.EnqueueEvent(ctx, &timeline2.CronScheduled{ - DeploymentKey: cronEvent.DeploymentKey, - Verb: cronEvent.Verb, - Time: cronEvent.Time, - ScheduledAt: cronEvent.ScheduledAt, - Schedule: cronEvent.Schedule, - Error: cronEvent.Error, - }) - time.Sleep(200 * time.Millisecond) - }) - - asyncEvent := &timeline2.AsyncExecuteEvent{ - AsyncExecute: timeline2.AsyncExecute{ - DeploymentKey: deploymentKey, - RequestKey: optional.Some(requestKey.String()), - EventType: timeline2.AsyncExecuteEventTypeCron, - Verb: schema.Ref{Module: "time", Name: "time"}, - Time: time.Now().Round(time.Millisecond), - Error: optional.None[string](), - }, - } - - t.Run("InsertAsyncExecuteEvent", func(t *testing.T) { - timeline.EnqueueEvent(ctx, &timeline2.AsyncExecute{ - DeploymentKey: asyncEvent.DeploymentKey, - RequestKey: asyncEvent.RequestKey, - EventType: asyncEvent.EventType, - Verb: asyncEvent.Verb, - Time: asyncEvent.Time, - Error: asyncEvent.Error, - }) - time.Sleep(200 * time.Millisecond) - }) - - pubSubPublishEvent := &timeline2.PubSubPublishEvent{ - Request: []byte("null"), - PubSubPublish: timeline2.PubSubPublish{ - DeploymentKey: deploymentKey, - RequestKey: optional.Some(requestKey.String()), - Time: time.Now().Round(time.Millisecond), - SourceVerb: schema.Ref{Module: "time", Name: "time"}, - Topic: "test", - Error: optional.None[string](), - }, - } - - t.Run("InsertPubSubPublishEvent", func(t *testing.T) { - timeline.EnqueueEvent(ctx, &timeline2.PubSubPublish{ - DeploymentKey: pubSubPublishEvent.DeploymentKey, - RequestKey: pubSubPublishEvent.RequestKey, - Time: pubSubPublishEvent.Time, - SourceVerb: pubSubPublishEvent.SourceVerb, - Topic: pubSubPublishEvent.Topic, - Error: pubSubPublishEvent.Error, - }) - time.Sleep(200 * time.Millisecond) - }) - - pubSubConsumeEvent := &timeline2.PubSubConsumeEvent{ - PubSubConsume: timeline2.PubSubConsume{ - DeploymentKey: deploymentKey, - RequestKey: optional.Some(requestKey.String()), - Time: time.Now().Round(time.Millisecond), - DestVerb: optional.Some(schema.RefKey{Module: "time", Name: "time"}), - Topic: "test", - Error: optional.None[string](), - }, - } - - t.Run("InsertPubSubConsumeEvent", func(t *testing.T) { - timeline.EnqueueEvent(ctx, &timeline2.PubSubConsume{ - DeploymentKey: pubSubConsumeEvent.DeploymentKey, - RequestKey: pubSubConsumeEvent.RequestKey, - Time: pubSubConsumeEvent.Time, - DestVerb: pubSubConsumeEvent.DestVerb, - Topic: pubSubConsumeEvent.Topic, - Error: pubSubConsumeEvent.Error, - }) - time.Sleep(200 * time.Millisecond) - }) - - expectedDeploymentUpdatedEvent := &timeline2.DeploymentUpdatedEvent{ - DeploymentKey: deploymentKey, - MinReplicas: 1, - } - - t.Run("QueryEvents", func(t *testing.T) { - t.Run("Limit", func(t *testing.T) { - events, err := timeline.QueryTimeline(ctx, 1) - assert.NoError(t, err) - assert.Equal(t, 1, len(events)) - }) - - t.Run("NoFilters", func(t *testing.T) { - events, err := timeline.QueryTimeline(ctx, 1000) - assert.NoError(t, err) - assertEventsEqual(t, []timeline2.Event{expectedDeploymentUpdatedEvent, callEvent, logEvent, ingressEvent, cronEvent, asyncEvent, pubSubPublishEvent, pubSubConsumeEvent}, events) - }) - - t.Run("ByDeployment", func(t *testing.T) { - events, err := timeline.QueryTimeline(ctx, 1000, timeline2.FilterDeployments(deploymentKey)) - assert.NoError(t, err) - assertEventsEqual(t, []timeline2.Event{expectedDeploymentUpdatedEvent, callEvent, logEvent, ingressEvent, cronEvent, asyncEvent, pubSubPublishEvent, pubSubConsumeEvent}, events) - }) - - t.Run("ByCall", func(t *testing.T) { - events, err := timeline.QueryTimeline(ctx, 1000, timeline2.FilterTypes(timeline2.EventTypeCall), timeline2.FilterCall(optional.None[string](), "time", optional.None[string]())) - assert.NoError(t, err) - assertEventsEqual(t, []timeline2.Event{callEvent}, events) - }) - - t.Run("ByModule", func(t *testing.T) { - eventTypes := []timeline2.EventType{ - timeline2.EventTypeCall, - timeline2.EventTypeIngress, - timeline2.EventTypeAsyncExecute, - timeline2.EventTypePubSubPublish, - timeline2.EventTypePubSubConsume, - } - events, err := timeline.QueryTimeline(ctx, 1000, timeline2.FilterTypes(eventTypes...), timeline2.FilterModule("time", optional.None[string]())) - assert.NoError(t, err) - assertEventsEqual(t, []timeline2.Event{callEvent, ingressEvent, asyncEvent, pubSubPublishEvent, pubSubConsumeEvent}, events) - }) - - t.Run("ByModuleWithVerb", func(t *testing.T) { - events, err := timeline.QueryTimeline(ctx, 1000, timeline2.FilterTypes(timeline2.EventTypeIngress), timeline2.FilterModule("time", optional.Some("time"))) - assert.NoError(t, err) - assertEventsEqual(t, []timeline2.Event{ingressEvent}, events) - }) - - t.Run("ByLogLevel", func(t *testing.T) { - events, err := timeline.QueryTimeline(ctx, 1000, timeline2.FilterTypes(timeline2.EventTypeLog), timeline2.FilterLogLevel(log.Trace)) - assert.NoError(t, err) - assertEventsEqual(t, []timeline2.Event{logEvent}, events) - }) - - t.Run("ByRequests", func(t *testing.T) { - events, err := timeline.QueryTimeline(ctx, 1000, timeline2.FilterRequests(requestKey)) - assert.NoError(t, err) - assertEventsEqual(t, []timeline2.Event{callEvent, logEvent, ingressEvent, asyncEvent, pubSubPublishEvent, pubSubConsumeEvent}, events) - }) - }) -} - -func normaliseEvents(events []timeline2.Event) []timeline2.Event { - for i := range events { - event := events[i] - re := reflect.Indirect(reflect.ValueOf(event)) - f := re.FieldByName("Time") - f.Set(reflect.Zero(f.Type())) - f = re.FieldByName("ID") - f.Set(reflect.Zero(f.Type())) - events[i] = event - } - - return events -} - -func assertEventsEqual(t *testing.T, expected, actual []timeline2.Event) { - t.Helper() - assert.Equal(t, normaliseEvents(expected), normaliseEvents(actual), assert.Exclude[time.Duration](), assert.Exclude[time.Time]()) -} - -func TestDeleteOldEvents(t *testing.T) { - ctx := log.ContextWithNewDefaultLogger(context.Background()) - conn := sqltest.OpenForTesting(ctx, t) - encryption, err := encryption.New(ctx, conn, encryption.NewBuilder()) - assert.NoError(t, err) - - timeline := timeline2.New(ctx, conn, encryption) - registry := artefacts.NewForTesting() - pubSub := pubsub.New(ctx, conn, encryption, optional.None[pubsub.AsyncCallListener](), timeline) - controllerDAL := controllerdal.New(ctx, conn, encryption, pubSub, registry) - - var testContent = bytes.Repeat([]byte("sometestcontentthatislongerthanthereadbuffer"), 100) - var testSha sha256.SHA256 - - t.Run("CreateArtefact", func(t *testing.T) { - testSha, err = registry.Upload(ctx, artefacts.Artefact{Content: testContent}) - assert.NoError(t, err) - }) - - module := &schema.Module{Name: "test"} - var deploymentKey model.DeploymentKey - t.Run("CreateDeployment", func(t *testing.T) { - deploymentKey, err = controllerDAL.CreateDeployment(ctx, "go", module, []dalmodel.DeploymentArtefact{{ - Digest: testSha, - Executable: true, - Path: "dir/filename", - }}) - assert.NoError(t, err) - }) - - requestKey := model.NewRequestKey(model.OriginIngress, "GET /test") - // week old event - callEvent := &timeline2.CallEvent{ - Time: time.Now().Add(-24 * 7 * time.Hour).Round(time.Millisecond), - DeploymentKey: deploymentKey, - RequestKey: optional.Some(requestKey), - Request: []byte("{}"), - Response: []byte(`{"time": "now"}`), - DestVerb: schema.Ref{Module: "time", Name: "time"}, - } - - t.Run("InsertCallEvent", func(t *testing.T) { - call := timeline2.CallEventToCallForTesting(callEvent) - timeline.EnqueueEvent(ctx, call) - time.Sleep(200 * time.Millisecond) - }) - // hour old event - callEvent = &timeline2.CallEvent{ - Time: time.Now().Add(-1 * time.Hour).Round(time.Millisecond), - DeploymentKey: deploymentKey, - RequestKey: optional.Some(requestKey), - Request: []byte("{}"), - Response: []byte(`{"time": "now"}`), - DestVerb: schema.Ref{Module: "time", Name: "time"}, - } - t.Run("InsertCallEvent", func(t *testing.T) { - call := timeline2.CallEventToCallForTesting(callEvent) - timeline.EnqueueEvent(ctx, call) - time.Sleep(200 * time.Millisecond) - }) - - // week old event - logEvent := &timeline2.LogEvent{ - Log: timeline2.Log{ - Time: time.Now().Add(-24 * 7 * time.Hour).Round(time.Millisecond), - DeploymentKey: deploymentKey, - RequestKey: optional.Some(requestKey), - Level: int32(log.Warn), - Attributes: map[string]string{"attr": "value"}, - Message: "A log entry", - }, - } - t.Run("InsertLogEntry", func(t *testing.T) { - timeline.EnqueueEvent(ctx, &logEvent.Log) - time.Sleep(200 * time.Millisecond) - }) - - // hour old event - logEvent = &timeline2.LogEvent{ - Log: timeline2.Log{ - Time: time.Now().Add(-1 * time.Hour).Round(time.Millisecond), - DeploymentKey: deploymentKey, - RequestKey: optional.Some(requestKey), - Level: int32(log.Warn), - Attributes: map[string]string{"attr": "value"}, - Message: "A log entry", - }, - } - t.Run("InsertLogEntry", func(t *testing.T) { - timeline.EnqueueEvent(ctx, &logEvent.Log) - time.Sleep(200 * time.Millisecond) - }) - - t.Run("DeleteOldEvents", func(t *testing.T) { - count, err := timeline.DeleteOldEvents(ctx, timeline2.EventTypeCall, 2*24*time.Hour) - assert.NoError(t, err) - assert.Equal(t, int64(1), count) - - count, err = timeline.DeleteOldEvents(ctx, timeline2.EventTypeLog, time.Minute) - assert.NoError(t, err) - assert.Equal(t, int64(2), count) - - count, err = timeline.DeleteOldEvents(ctx, timeline2.EventTypeLog, time.Minute) - assert.NoError(t, err) - assert.Equal(t, int64(0), count) - }) -} diff --git a/backend/controller/timeline/timeline.go b/backend/controller/timeline/timeline.go index 4220c04837..2bda7d5d6e 100644 --- a/backend/controller/timeline/timeline.go +++ b/backend/controller/timeline/timeline.go @@ -3,16 +3,12 @@ package timeline import ( "context" stdsql "database/sql" - "fmt" "time" "github.com/alecthomas/atomic" "github.com/TBD54566975/ftl/backend/controller/encryption" - "github.com/TBD54566975/ftl/backend/controller/observability" - "github.com/TBD54566975/ftl/backend/controller/sql/sqltypes" "github.com/TBD54566975/ftl/backend/controller/timeline/internal/sql" - "github.com/TBD54566975/ftl/backend/libdal" "github.com/TBD54566975/ftl/internal/log" ) @@ -29,9 +25,6 @@ const ( EventTypeAsyncExecute = sql.EventTypeAsyncExecute EventTypePubSubPublish = sql.EventTypePubsubPublish EventTypePubSubConsume = sql.EventTypePubsubConsume - - maxBatchSize = 16 - maxBatchDelay = 100 * time.Millisecond ) // Event types. @@ -65,15 +58,9 @@ func New(ctx context.Context, conn *stdsql.DB, encryption *encryption.Service) * encryption: encryption, events: events, } - go s.processEvents() return s } -func (s *Service) DeleteOldEvents(ctx context.Context, eventType EventType, age time.Duration) (int64, error) { - count, err := sql.New(s.conn).DeleteOldTimelineEvents(ctx, sqltypes.Duration(age), eventType) - return count, libdal.TranslatePGError(err) -} - // EnqueueEvent asynchronously enqueues an event for insertion into the timeline. func (s *Service) EnqueueEvent(ctx context.Context, inEvent InEvent) { event, err := inEvent.toEvent() @@ -90,80 +77,3 @@ func (s *Service) EnqueueEvent(ctx context.Context, inEvent InEvent) { } } } - -func (s *Service) processEvents() { - lastFlush := time.Now() - buffer := make([]Event, 0, maxBatchSize) - for { - select { - case event := <-s.events: - buffer = append(buffer, event) - - if len(buffer) < maxBatchSize || time.Since(lastFlush) < maxBatchDelay { - continue - } - s.flushEvents(buffer) - buffer = nil - - case <-time.After(maxBatchDelay): - if len(buffer) == 0 { - continue - } - s.flushEvents(buffer) - buffer = nil - } - } -} - -// Flush all events in the buffer to the database in a single transaction. -func (s *Service) flushEvents(events []Event) { - logger := log.FromContext(s.ctx).Scope("timeline") - tx, err := s.conn.Begin() - if err != nil { - logger.Errorf(err, "Failed to start transaction") - return - } - querier := sql.New(tx) - var lastError error - failures := 0 - for _, event := range events { - var err error - switch e := event.(type) { - case *CallEvent: - err = s.insertCallEvent(s.ctx, querier, e) - case *LogEvent: - err = s.insertLogEvent(s.ctx, querier, e) - case *IngressEvent: - err = s.insertHTTPIngress(s.ctx, querier, e) - case *CronScheduledEvent: - err = s.insertCronScheduledEvent(s.ctx, querier, e) - case *AsyncExecuteEvent: - err = s.insertAsyncExecuteEvent(s.ctx, querier, e) - case *PubSubPublishEvent: - err = s.insertPubSubPublishEvent(s.ctx, querier, e) - case *PubSubConsumeEvent: - err = s.insertPubSubConsumeEvent(s.ctx, querier, e) - case *DeploymentCreatedEvent, *DeploymentUpdatedEvent: - // TODO: Implement - default: - panic(fmt.Sprintf("unexpected event type: %T", e)) - } - if err != nil { - lastError = err - failures++ - } - } - err = tx.Commit() - if err != nil { - failures = len(events) - lastError = err - } - if lastError != nil { - if time.Since(s.lastFailedError.Load()) > 10*time.Second { - logger.Errorf(lastError, "Failed to insert %d events, most recent error", failures) - s.lastFailedError.Store(time.Now()) - } - observability.Timeline.Failed(s.ctx, failures) - } - observability.Timeline.Inserted(s.ctx, len(events)-failures) -} diff --git a/backend/ingress/handler.go b/backend/ingress/handler.go index 9ea343976a..0e924cd3e5 100644 --- a/backend/ingress/handler.go +++ b/backend/ingress/handler.go @@ -12,10 +12,10 @@ import ( "github.com/alecthomas/types/optional" "github.com/TBD54566975/ftl/backend/controller/observability" - "github.com/TBD54566975/ftl/backend/controller/timeline" "github.com/TBD54566975/ftl/backend/libdal" schemapb "github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/schema/v1" ftlv1 "github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/v1" + "github.com/TBD54566975/ftl/backend/timeline" "github.com/TBD54566975/ftl/internal/log" "github.com/TBD54566975/ftl/internal/model" "github.com/TBD54566975/ftl/internal/routing" diff --git a/backend/protos/xyz/block/ftl/timeline/v1/event.pb.go b/backend/protos/xyz/block/ftl/timeline/v1/event.pb.go index f171432a6c..99a4e3d55d 100644 --- a/backend/protos/xyz/block/ftl/timeline/v1/event.pb.go +++ b/backend/protos/xyz/block/ftl/timeline/v1/event.pb.go @@ -207,7 +207,7 @@ type LogEvent struct { DeploymentKey string `protobuf:"bytes,1,opt,name=deployment_key,json=deploymentKey,proto3" json:"deployment_key,omitempty"` RequestKey *string `protobuf:"bytes,2,opt,name=request_key,json=requestKey,proto3,oneof" json:"request_key,omitempty"` - TimeStamp *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=time_stamp,json=timeStamp,proto3" json:"time_stamp,omitempty"` + Timestamp *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=timestamp,proto3" json:"timestamp,omitempty"` LogLevel int32 `protobuf:"varint,4,opt,name=log_level,json=logLevel,proto3" json:"log_level,omitempty"` Attributes map[string]string `protobuf:"bytes,5,rep,name=attributes,proto3" json:"attributes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` Message string `protobuf:"bytes,6,opt,name=message,proto3" json:"message,omitempty"` @@ -259,9 +259,9 @@ func (x *LogEvent) GetRequestKey() string { return "" } -func (x *LogEvent) GetTimeStamp() *timestamppb.Timestamp { +func (x *LogEvent) GetTimestamp() *timestamppb.Timestamp { if x != nil { - return x.TimeStamp + return x.Timestamp } return nil } @@ -308,7 +308,7 @@ type CallEvent struct { RequestKey *string `protobuf:"bytes,1,opt,name=request_key,json=requestKey,proto3,oneof" json:"request_key,omitempty"` DeploymentKey string `protobuf:"bytes,2,opt,name=deployment_key,json=deploymentKey,proto3" json:"deployment_key,omitempty"` - TimeStamp *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=time_stamp,json=timeStamp,proto3" json:"time_stamp,omitempty"` + Timestamp *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=timestamp,proto3" json:"timestamp,omitempty"` SourceVerbRef *v1.Ref `protobuf:"bytes,11,opt,name=source_verb_ref,json=sourceVerbRef,proto3,oneof" json:"source_verb_ref,omitempty"` DestinationVerbRef *v1.Ref `protobuf:"bytes,12,opt,name=destination_verb_ref,json=destinationVerbRef,proto3" json:"destination_verb_ref,omitempty"` Duration *durationpb.Duration `protobuf:"bytes,6,opt,name=duration,proto3" json:"duration,omitempty"` @@ -362,9 +362,9 @@ func (x *CallEvent) GetDeploymentKey() string { return "" } -func (x *CallEvent) GetTimeStamp() *timestamppb.Timestamp { +func (x *CallEvent) GetTimestamp() *timestamppb.Timestamp { if x != nil { - return x.TimeStamp + return x.Timestamp } return nil } @@ -567,7 +567,7 @@ type IngressEvent struct { Method string `protobuf:"bytes,4,opt,name=method,proto3" json:"method,omitempty"` Path string `protobuf:"bytes,5,opt,name=path,proto3" json:"path,omitempty"` StatusCode int32 `protobuf:"varint,7,opt,name=status_code,json=statusCode,proto3" json:"status_code,omitempty"` - TimeStamp *timestamppb.Timestamp `protobuf:"bytes,8,opt,name=time_stamp,json=timeStamp,proto3" json:"time_stamp,omitempty"` + Timestamp *timestamppb.Timestamp `protobuf:"bytes,8,opt,name=timestamp,proto3" json:"timestamp,omitempty"` Duration *durationpb.Duration `protobuf:"bytes,9,opt,name=duration,proto3" json:"duration,omitempty"` Request string `protobuf:"bytes,10,opt,name=request,proto3" json:"request,omitempty"` RequestHeader string `protobuf:"bytes,11,opt,name=request_header,json=requestHeader,proto3" json:"request_header,omitempty"` @@ -648,9 +648,9 @@ func (x *IngressEvent) GetStatusCode() int32 { return 0 } -func (x *IngressEvent) GetTimeStamp() *timestamppb.Timestamp { +func (x *IngressEvent) GetTimestamp() *timestamppb.Timestamp { if x != nil { - return x.TimeStamp + return x.Timestamp } return nil } @@ -704,7 +704,7 @@ type CronScheduledEvent struct { DeploymentKey string `protobuf:"bytes,1,opt,name=deployment_key,json=deploymentKey,proto3" json:"deployment_key,omitempty"` VerbRef *v1.Ref `protobuf:"bytes,2,opt,name=verb_ref,json=verbRef,proto3" json:"verb_ref,omitempty"` - TimeStamp *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=time_stamp,json=timeStamp,proto3" json:"time_stamp,omitempty"` + Timestamp *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=timestamp,proto3" json:"timestamp,omitempty"` Duration *durationpb.Duration `protobuf:"bytes,4,opt,name=duration,proto3" json:"duration,omitempty"` ScheduledAt *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=scheduled_at,json=scheduledAt,proto3" json:"scheduled_at,omitempty"` Schedule string `protobuf:"bytes,6,opt,name=schedule,proto3" json:"schedule,omitempty"` @@ -755,9 +755,9 @@ func (x *CronScheduledEvent) GetVerbRef() *v1.Ref { return nil } -func (x *CronScheduledEvent) GetTimeStamp() *timestamppb.Timestamp { +func (x *CronScheduledEvent) GetTimestamp() *timestamppb.Timestamp { if x != nil { - return x.TimeStamp + return x.Timestamp } return nil } @@ -798,7 +798,7 @@ type AsyncExecuteEvent struct { DeploymentKey string `protobuf:"bytes,1,opt,name=deployment_key,json=deploymentKey,proto3" json:"deployment_key,omitempty"` RequestKey *string `protobuf:"bytes,2,opt,name=request_key,json=requestKey,proto3,oneof" json:"request_key,omitempty"` VerbRef *v1.Ref `protobuf:"bytes,3,opt,name=verb_ref,json=verbRef,proto3" json:"verb_ref,omitempty"` - TimeStamp *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=time_stamp,json=timeStamp,proto3" json:"time_stamp,omitempty"` + Timestamp *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=timestamp,proto3" json:"timestamp,omitempty"` Duration *durationpb.Duration `protobuf:"bytes,5,opt,name=duration,proto3" json:"duration,omitempty"` AsyncEventType AsyncExecuteEventType `protobuf:"varint,6,opt,name=async_event_type,json=asyncEventType,proto3,enum=xyz.block.ftl.timeline.v1.AsyncExecuteEventType" json:"async_event_type,omitempty"` Error *string `protobuf:"bytes,7,opt,name=error,proto3,oneof" json:"error,omitempty"` @@ -855,9 +855,9 @@ func (x *AsyncExecuteEvent) GetVerbRef() *v1.Ref { return nil } -func (x *AsyncExecuteEvent) GetTimeStamp() *timestamppb.Timestamp { +func (x *AsyncExecuteEvent) GetTimestamp() *timestamppb.Timestamp { if x != nil { - return x.TimeStamp + return x.Timestamp } return nil } @@ -891,7 +891,7 @@ type PubSubPublishEvent struct { DeploymentKey string `protobuf:"bytes,1,opt,name=deployment_key,json=deploymentKey,proto3" json:"deployment_key,omitempty"` RequestKey *string `protobuf:"bytes,2,opt,name=request_key,json=requestKey,proto3,oneof" json:"request_key,omitempty"` VerbRef *v1.Ref `protobuf:"bytes,3,opt,name=verb_ref,json=verbRef,proto3" json:"verb_ref,omitempty"` - TimeStamp *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=time_stamp,json=timeStamp,proto3" json:"time_stamp,omitempty"` + Timestamp *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=timestamp,proto3" json:"timestamp,omitempty"` Duration *durationpb.Duration `protobuf:"bytes,5,opt,name=duration,proto3" json:"duration,omitempty"` Topic string `protobuf:"bytes,6,opt,name=topic,proto3" json:"topic,omitempty"` Request string `protobuf:"bytes,7,opt,name=request,proto3" json:"request,omitempty"` @@ -949,9 +949,9 @@ func (x *PubSubPublishEvent) GetVerbRef() *v1.Ref { return nil } -func (x *PubSubPublishEvent) GetTimeStamp() *timestamppb.Timestamp { +func (x *PubSubPublishEvent) GetTimestamp() *timestamppb.Timestamp { if x != nil { - return x.TimeStamp + return x.Timestamp } return nil } @@ -993,7 +993,7 @@ type PubSubConsumeEvent struct { RequestKey *string `protobuf:"bytes,2,opt,name=request_key,json=requestKey,proto3,oneof" json:"request_key,omitempty"` DestVerbModule *string `protobuf:"bytes,3,opt,name=dest_verb_module,json=destVerbModule,proto3,oneof" json:"dest_verb_module,omitempty"` DestVerbName *string `protobuf:"bytes,4,opt,name=dest_verb_name,json=destVerbName,proto3,oneof" json:"dest_verb_name,omitempty"` - TimeStamp *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=time_stamp,json=timeStamp,proto3" json:"time_stamp,omitempty"` + Timestamp *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=timestamp,proto3" json:"timestamp,omitempty"` Duration *durationpb.Duration `protobuf:"bytes,6,opt,name=duration,proto3" json:"duration,omitempty"` Topic string `protobuf:"bytes,7,opt,name=topic,proto3" json:"topic,omitempty"` Error *string `protobuf:"bytes,8,opt,name=error,proto3,oneof" json:"error,omitempty"` @@ -1057,9 +1057,9 @@ func (x *PubSubConsumeEvent) GetDestVerbName() string { return "" } -func (x *PubSubConsumeEvent) GetTimeStamp() *timestamppb.Timestamp { +func (x *PubSubConsumeEvent) GetTimestamp() *timestamppb.Timestamp { if x != nil { - return x.TimeStamp + return x.Timestamp } return nil } @@ -1090,7 +1090,7 @@ type Event struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - TimeStamp *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=time_stamp,json=timeStamp,proto3" json:"time_stamp,omitempty"` + Timestamp *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` // Unique ID for event. Id int64 `protobuf:"varint,2,opt,name=id,proto3" json:"id,omitempty"` // Types that are assignable to Entry: @@ -1137,9 +1137,9 @@ func (*Event) Descriptor() ([]byte, []int) { return file_xyz_block_ftl_timeline_v1_event_proto_rawDescGZIP(), []int{9} } -func (x *Event) GetTimeStamp() *timestamppb.Timestamp { +func (x *Event) GetTimestamp() *timestamppb.Timestamp { if x != nil { - return x.TimeStamp + return x.Timestamp } return nil } @@ -1292,313 +1292,312 @@ var file_xyz_block_ftl_timeline_v1_event_proto_rawDesc = []byte{ 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x24, 0x78, 0x79, 0x7a, 0x2f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2f, 0x66, 0x74, 0x6c, 0x2f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x63, 0x68, - 0x65, 0x6d, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb7, 0x03, 0x0a, 0x08, 0x4c, 0x6f, + 0x65, 0x6d, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb6, 0x03, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x24, 0x0a, 0x0b, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4b, 0x65, 0x79, - 0x88, 0x01, 0x01, 0x12, 0x39, 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x53, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1b, - 0x0a, 0x09, 0x6c, 0x6f, 0x67, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x05, 0x52, 0x08, 0x6c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x53, 0x0a, 0x0a, 0x61, - 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x33, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, - 0x74, 0x69, 0x6d, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x45, - 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, - 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x19, 0x0a, 0x05, 0x65, 0x72, - 0x72, 0x6f, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x05, 0x65, 0x72, 0x72, - 0x6f, 0x72, 0x88, 0x01, 0x01, 0x12, 0x19, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x18, 0x08, - 0x20, 0x01, 0x28, 0x09, 0x48, 0x02, 0x52, 0x05, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x88, 0x01, 0x01, - 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, - 0x0e, 0x0a, 0x0c, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x42, - 0x08, 0x0a, 0x06, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x73, 0x74, - 0x61, 0x63, 0x6b, 0x22, 0x95, 0x04, 0x0a, 0x09, 0x43, 0x61, 0x6c, 0x6c, 0x45, 0x76, 0x65, 0x6e, - 0x74, 0x12, 0x24, 0x0a, 0x0b, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x6b, 0x65, 0x79, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x4b, 0x65, 0x79, 0x88, 0x01, 0x01, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x65, 0x70, 0x6c, 0x6f, - 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0d, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x39, - 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, - 0x74, 0x69, 0x6d, 0x65, 0x53, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x49, 0x0a, 0x0f, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x62, 0x5f, 0x72, 0x65, 0x66, 0x18, 0x0b, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, - 0x74, 0x6c, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x66, - 0x48, 0x01, 0x52, 0x0d, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x62, 0x52, 0x65, - 0x66, 0x88, 0x01, 0x01, 0x12, 0x4e, 0x0a, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x5f, 0x76, 0x65, 0x72, 0x62, 0x5f, 0x72, 0x65, 0x66, 0x18, 0x0c, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, - 0x74, 0x6c, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x66, - 0x52, 0x12, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, - 0x62, 0x52, 0x65, 0x66, 0x12, 0x35, 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x72, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x19, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, - 0x48, 0x02, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x88, 0x01, 0x01, 0x12, 0x19, 0x0a, 0x05, - 0x73, 0x74, 0x61, 0x63, 0x6b, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x48, 0x03, 0x52, 0x05, 0x73, - 0x74, 0x61, 0x63, 0x6b, 0x88, 0x01, 0x01, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x72, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x42, 0x12, 0x0a, 0x10, 0x5f, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x62, 0x5f, 0x72, 0x65, 0x66, 0x42, 0x08, 0x0a, 0x06, 0x5f, - 0x65, 0x72, 0x72, 0x6f, 0x72, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x4a, - 0x04, 0x08, 0x04, 0x10, 0x05, 0x4a, 0x04, 0x08, 0x05, 0x10, 0x06, 0x22, 0xb8, 0x01, 0x0a, 0x16, - 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x61, 0x6e, 0x67, - 0x75, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x61, 0x6e, 0x67, - 0x75, 0x61, 0x67, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x6e, - 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x6f, 0x64, 0x75, 0x6c, - 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x6d, 0x69, 0x6e, 0x5f, 0x72, 0x65, 0x70, - 0x6c, 0x69, 0x63, 0x61, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x6d, 0x69, 0x6e, - 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x73, 0x12, 0x1f, 0x0a, 0x08, 0x72, 0x65, 0x70, 0x6c, - 0x61, 0x63, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x08, 0x72, 0x65, - 0x70, 0x6c, 0x61, 0x63, 0x65, 0x64, 0x88, 0x01, 0x01, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x72, 0x65, - 0x70, 0x6c, 0x61, 0x63, 0x65, 0x64, 0x22, 0x79, 0x0a, 0x16, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, - 0x6d, 0x65, 0x6e, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, - 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, - 0x65, 0x79, 0x12, 0x21, 0x0a, 0x0c, 0x6d, 0x69, 0x6e, 0x5f, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, - 0x61, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x6d, 0x69, 0x6e, 0x52, 0x65, 0x70, - 0x6c, 0x69, 0x63, 0x61, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x70, 0x72, 0x65, 0x76, 0x5f, 0x6d, 0x69, - 0x6e, 0x5f, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, - 0x52, 0x0f, 0x70, 0x72, 0x65, 0x76, 0x4d, 0x69, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, - 0x73, 0x22, 0x8e, 0x04, 0x0a, 0x0c, 0x49, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, - 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x64, 0x65, 0x70, 0x6c, - 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x24, 0x0a, 0x0b, 0x72, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, - 0x52, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x88, 0x01, 0x01, 0x12, - 0x37, 0x0a, 0x08, 0x76, 0x65, 0x72, 0x62, 0x5f, 0x72, 0x65, 0x66, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1c, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, - 0x6c, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x66, 0x52, - 0x07, 0x76, 0x65, 0x72, 0x62, 0x52, 0x65, 0x66, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, - 0x6f, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, - 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x70, 0x61, 0x74, 0x68, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, 0x63, - 0x6f, 0x64, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x39, 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x53, 0x74, 0x61, 0x6d, 0x70, - 0x12, 0x35, 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x64, - 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x68, 0x65, 0x61, - 0x64, 0x65, 0x72, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x72, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x72, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x19, 0x0a, - 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x05, - 0x65, 0x72, 0x72, 0x6f, 0x72, 0x88, 0x01, 0x01, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x72, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x65, 0x72, 0x72, - 0x6f, 0x72, 0x22, 0xe6, 0x02, 0x0a, 0x12, 0x43, 0x72, 0x6f, 0x6e, 0x53, 0x63, 0x68, 0x65, 0x64, - 0x75, 0x6c, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x65, 0x70, - 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0d, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, - 0x12, 0x37, 0x0a, 0x08, 0x76, 0x65, 0x72, 0x62, 0x5f, 0x72, 0x65, 0x66, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, - 0x74, 0x6c, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x66, - 0x52, 0x07, 0x76, 0x65, 0x72, 0x62, 0x52, 0x65, 0x66, 0x12, 0x39, 0x0a, 0x0a, 0x74, 0x69, 0x6d, - 0x65, 0x5f, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x53, - 0x74, 0x61, 0x6d, 0x70, 0x12, 0x35, 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3d, 0x0a, 0x0c, 0x73, - 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0b, 0x73, - 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x41, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x63, - 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x63, - 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x12, 0x19, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, - 0x07, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x88, 0x01, - 0x01, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x9c, 0x03, 0x0a, 0x11, - 0x41, 0x73, 0x79, 0x6e, 0x63, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, - 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, - 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x64, 0x65, 0x70, 0x6c, 0x6f, - 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x24, 0x0a, 0x0b, 0x72, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, - 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x88, 0x01, 0x01, 0x12, 0x37, - 0x0a, 0x08, 0x76, 0x65, 0x72, 0x62, 0x5f, 0x72, 0x65, 0x66, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x88, 0x01, 0x01, 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1b, 0x0a, + 0x09, 0x6c, 0x6f, 0x67, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x08, 0x6c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x53, 0x0a, 0x0a, 0x61, 0x74, + 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x33, + 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x74, + 0x69, 0x6d, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, + 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x19, 0x0a, 0x05, 0x65, 0x72, 0x72, + 0x6f, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, + 0x72, 0x88, 0x01, 0x01, 0x12, 0x19, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x18, 0x08, 0x20, + 0x01, 0x28, 0x09, 0x48, 0x02, 0x52, 0x05, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x88, 0x01, 0x01, 0x1a, + 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x0e, + 0x0a, 0x0c, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x42, 0x08, + 0x0a, 0x06, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x73, 0x74, 0x61, + 0x63, 0x6b, 0x22, 0x94, 0x04, 0x0a, 0x09, 0x43, 0x61, 0x6c, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x12, 0x24, 0x0a, 0x0b, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x4b, 0x65, 0x79, 0x88, 0x01, 0x01, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, + 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, + 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x38, 0x0a, + 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x49, 0x0a, 0x0f, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x5f, 0x76, 0x65, 0x72, 0x62, 0x5f, 0x72, 0x65, 0x66, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, - 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x66, 0x52, 0x07, - 0x76, 0x65, 0x72, 0x62, 0x52, 0x65, 0x66, 0x12, 0x39, 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x5f, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x53, 0x74, 0x61, - 0x6d, 0x70, 0x12, 0x35, 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x5a, 0x0a, 0x10, 0x61, 0x73, 0x79, - 0x6e, 0x63, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x06, 0x20, - 0x01, 0x28, 0x0e, 0x32, 0x30, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, - 0x66, 0x74, 0x6c, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x41, 0x73, 0x79, 0x6e, 0x63, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, - 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0e, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x45, 0x76, 0x65, 0x6e, - 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x19, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x07, - 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x88, 0x01, 0x01, - 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x6b, 0x65, 0x79, - 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0xf1, 0x02, 0x0a, 0x12, 0x50, - 0x75, 0x62, 0x53, 0x75, 0x62, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x45, 0x76, 0x65, 0x6e, - 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, - 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x64, 0x65, 0x70, 0x6c, 0x6f, - 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x24, 0x0a, 0x0b, 0x72, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, - 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x88, 0x01, 0x01, 0x12, 0x37, - 0x0a, 0x08, 0x76, 0x65, 0x72, 0x62, 0x5f, 0x72, 0x65, 0x66, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x66, 0x48, 0x01, + 0x52, 0x0d, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x62, 0x52, 0x65, 0x66, 0x88, + 0x01, 0x01, 0x12, 0x4e, 0x0a, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x76, 0x65, 0x72, 0x62, 0x5f, 0x72, 0x65, 0x66, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, - 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x66, 0x52, 0x07, - 0x76, 0x65, 0x72, 0x62, 0x52, 0x65, 0x66, 0x12, 0x39, 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x5f, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x53, 0x74, 0x61, - 0x6d, 0x70, 0x12, 0x35, 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, + 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x66, 0x52, 0x12, + 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x62, 0x52, + 0x65, 0x66, 0x12, 0x35, 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x70, - 0x69, 0x63, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x12, - 0x18, 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x05, 0x65, 0x72, 0x72, - 0x6f, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, - 0x72, 0x88, 0x01, 0x01, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x5f, 0x6b, 0x65, 0x79, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0xa0, - 0x03, 0x0a, 0x12, 0x50, 0x75, 0x62, 0x53, 0x75, 0x62, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, - 0x65, 0x6e, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x64, - 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x24, 0x0a, 0x0b, - 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x48, 0x00, 0x52, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x88, - 0x01, 0x01, 0x12, 0x2d, 0x0a, 0x10, 0x64, 0x65, 0x73, 0x74, 0x5f, 0x76, 0x65, 0x72, 0x62, 0x5f, - 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x0e, - 0x64, 0x65, 0x73, 0x74, 0x56, 0x65, 0x72, 0x62, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x88, 0x01, - 0x01, 0x12, 0x29, 0x0a, 0x0e, 0x64, 0x65, 0x73, 0x74, 0x5f, 0x76, 0x65, 0x72, 0x62, 0x5f, 0x6e, - 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x02, 0x52, 0x0c, 0x64, 0x65, 0x73, - 0x74, 0x56, 0x65, 0x72, 0x62, 0x4e, 0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, 0x39, 0x0a, 0x0a, - 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, - 0x6d, 0x65, 0x53, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x35, 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, - 0x0a, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, - 0x6f, 0x70, 0x69, 0x63, 0x12, 0x19, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x08, 0x20, - 0x01, 0x28, 0x09, 0x48, 0x03, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x88, 0x01, 0x01, 0x42, - 0x0e, 0x0a, 0x0c, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x42, - 0x13, 0x0a, 0x11, 0x5f, 0x64, 0x65, 0x73, 0x74, 0x5f, 0x76, 0x65, 0x72, 0x62, 0x5f, 0x6d, 0x6f, - 0x64, 0x75, 0x6c, 0x65, 0x42, 0x11, 0x0a, 0x0f, 0x5f, 0x64, 0x65, 0x73, 0x74, 0x5f, 0x76, 0x65, - 0x72, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x65, 0x72, 0x72, 0x6f, - 0x72, 0x22, 0xba, 0x06, 0x0a, 0x05, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x74, - 0x69, 0x6d, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, - 0x65, 0x53, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x37, 0x0a, 0x03, 0x6c, 0x6f, 0x67, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, - 0x66, 0x74, 0x6c, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x4c, 0x6f, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x03, 0x6c, 0x6f, 0x67, 0x12, - 0x3a, 0x0a, 0x04, 0x63, 0x61, 0x6c, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, - 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x74, 0x69, - 0x6d, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x45, 0x76, - 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x04, 0x63, 0x61, 0x6c, 0x6c, 0x12, 0x62, 0x0a, 0x12, 0x64, - 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, - 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x6c, 0x69, 0x6e, 0x65, - 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x43, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x11, 0x64, 0x65, - 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x12, - 0x62, 0x0a, 0x12, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x75, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x78, 0x79, + 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, + 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x19, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x48, 0x02, + 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x88, 0x01, 0x01, 0x12, 0x19, 0x0a, 0x05, 0x73, 0x74, + 0x61, 0x63, 0x6b, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x48, 0x03, 0x52, 0x05, 0x73, 0x74, 0x61, + 0x63, 0x6b, 0x88, 0x01, 0x01, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x42, 0x12, 0x0a, 0x10, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x5f, 0x76, 0x65, 0x72, 0x62, 0x5f, 0x72, 0x65, 0x66, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x65, 0x72, + 0x72, 0x6f, 0x72, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x4a, 0x04, 0x08, + 0x04, 0x10, 0x05, 0x4a, 0x04, 0x08, 0x05, 0x10, 0x06, 0x22, 0xb8, 0x01, 0x0a, 0x16, 0x44, 0x65, + 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, + 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, + 0x67, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x4e, + 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x6d, 0x69, 0x6e, 0x5f, 0x72, 0x65, 0x70, 0x6c, 0x69, + 0x63, 0x61, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x6d, 0x69, 0x6e, 0x52, 0x65, + 0x70, 0x6c, 0x69, 0x63, 0x61, 0x73, 0x12, 0x1f, 0x0a, 0x08, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, + 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x08, 0x72, 0x65, 0x70, 0x6c, + 0x61, 0x63, 0x65, 0x64, 0x88, 0x01, 0x01, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x72, 0x65, 0x70, 0x6c, + 0x61, 0x63, 0x65, 0x64, 0x22, 0x79, 0x0a, 0x16, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, + 0x6e, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x10, + 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, + 0x12, 0x21, 0x0a, 0x0c, 0x6d, 0x69, 0x6e, 0x5f, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x73, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x6d, 0x69, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x69, + 0x63, 0x61, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x70, 0x72, 0x65, 0x76, 0x5f, 0x6d, 0x69, 0x6e, 0x5f, + 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, + 0x70, 0x72, 0x65, 0x76, 0x4d, 0x69, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x73, 0x22, + 0x8d, 0x04, 0x0a, 0x0c, 0x49, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x6b, + 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, + 0x6d, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x24, 0x0a, 0x0b, 0x72, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0a, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x88, 0x01, 0x01, 0x12, 0x37, 0x0a, + 0x08, 0x76, 0x65, 0x72, 0x62, 0x5f, 0x72, 0x65, 0x66, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1c, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, + 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x66, 0x52, 0x07, 0x76, + 0x65, 0x72, 0x62, 0x52, 0x65, 0x66, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x12, + 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, + 0x74, 0x68, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, 0x63, 0x6f, 0x64, + 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, + 0x6f, 0x64, 0x65, 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x35, 0x0a, + 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x64, 0x75, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, + 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x25, + 0x0a, 0x0e, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, + 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, + 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x68, 0x65, + 0x61, 0x64, 0x65, 0x72, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x72, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x19, 0x0a, 0x05, 0x65, 0x72, + 0x72, 0x6f, 0x72, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x05, 0x65, 0x72, 0x72, + 0x6f, 0x72, 0x88, 0x01, 0x01, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, + 0xe5, 0x02, 0x0a, 0x12, 0x43, 0x72, 0x6f, 0x6e, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, + 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, + 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, + 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x37, 0x0a, + 0x08, 0x76, 0x65, 0x72, 0x62, 0x5f, 0x72, 0x65, 0x66, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1c, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, + 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x66, 0x52, 0x07, 0x76, + 0x65, 0x72, 0x62, 0x52, 0x65, 0x66, 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x12, 0x35, 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x64, + 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3d, 0x0a, 0x0c, 0x73, 0x63, 0x68, 0x65, 0x64, + 0x75, 0x6c, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0b, 0x73, 0x63, 0x68, 0x65, 0x64, + 0x75, 0x6c, 0x65, 0x64, 0x41, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, + 0x6c, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, + 0x6c, 0x65, 0x12, 0x19, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x09, 0x48, 0x00, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x88, 0x01, 0x01, 0x42, 0x08, 0x0a, + 0x06, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x9b, 0x03, 0x0a, 0x11, 0x41, 0x73, 0x79, 0x6e, + 0x63, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x25, 0x0a, + 0x0e, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, + 0x74, 0x4b, 0x65, 0x79, 0x12, 0x24, 0x0a, 0x0b, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, + 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0a, 0x72, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x88, 0x01, 0x01, 0x12, 0x37, 0x0a, 0x08, 0x76, 0x65, + 0x72, 0x62, 0x5f, 0x72, 0x65, 0x66, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x78, + 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x73, 0x63, 0x68, + 0x65, 0x6d, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x66, 0x52, 0x07, 0x76, 0x65, 0x72, 0x62, + 0x52, 0x65, 0x66, 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x35, 0x0a, + 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x64, 0x75, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x5a, 0x0a, 0x10, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x65, 0x76, + 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x30, + 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x74, + 0x69, 0x6d, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x73, 0x79, 0x6e, 0x63, + 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, + 0x52, 0x0e, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, + 0x12, 0x19, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x48, + 0x01, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x88, 0x01, 0x01, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x42, 0x08, 0x0a, 0x06, 0x5f, + 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0xf0, 0x02, 0x0a, 0x12, 0x50, 0x75, 0x62, 0x53, 0x75, 0x62, + 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x25, 0x0a, 0x0e, + 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, + 0x4b, 0x65, 0x79, 0x12, 0x24, 0x0a, 0x0b, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x6b, + 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0a, 0x72, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x88, 0x01, 0x01, 0x12, 0x37, 0x0a, 0x08, 0x76, 0x65, 0x72, + 0x62, 0x5f, 0x72, 0x65, 0x66, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x78, 0x79, + 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x73, 0x63, 0x68, 0x65, + 0x6d, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x66, 0x52, 0x07, 0x76, 0x65, 0x72, 0x62, 0x52, + 0x65, 0x66, 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x35, 0x0a, 0x08, + 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x09, 0x48, 0x01, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x88, 0x01, 0x01, 0x42, 0x0e, + 0x0a, 0x0c, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x42, 0x08, + 0x0a, 0x06, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x9f, 0x03, 0x0a, 0x12, 0x50, 0x75, 0x62, + 0x53, 0x75, 0x62, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, + 0x25, 0x0a, 0x0e, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x6b, 0x65, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, + 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x24, 0x0a, 0x0b, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0a, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x88, 0x01, 0x01, 0x12, 0x2d, 0x0a, 0x10, + 0x64, 0x65, 0x73, 0x74, 0x5f, 0x76, 0x65, 0x72, 0x62, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x0e, 0x64, 0x65, 0x73, 0x74, 0x56, 0x65, + 0x72, 0x62, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x88, 0x01, 0x01, 0x12, 0x29, 0x0a, 0x0e, 0x64, + 0x65, 0x73, 0x74, 0x5f, 0x76, 0x65, 0x72, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x48, 0x02, 0x52, 0x0c, 0x64, 0x65, 0x73, 0x74, 0x56, 0x65, 0x72, 0x62, 0x4e, + 0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x12, 0x35, 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x64, + 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x12, 0x19, 0x0a, + 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x48, 0x03, 0x52, 0x05, + 0x65, 0x72, 0x72, 0x6f, 0x72, 0x88, 0x01, 0x01, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x72, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x64, 0x65, 0x73, + 0x74, 0x5f, 0x76, 0x65, 0x72, 0x62, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x42, 0x11, 0x0a, + 0x0f, 0x5f, 0x64, 0x65, 0x73, 0x74, 0x5f, 0x76, 0x65, 0x72, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, + 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0xb9, 0x06, 0x0a, 0x05, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x0e, + 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x37, + 0x0a, 0x03, 0x6c, 0x6f, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x74, 0x69, 0x6d, 0x65, - 0x6c, 0x69, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, - 0x6e, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, - 0x52, 0x11, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x64, 0x12, 0x43, 0x0a, 0x07, 0x69, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x18, 0x07, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, - 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x2e, 0x76, 0x31, - 0x2e, 0x49, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, - 0x07, 0x69, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x56, 0x0a, 0x0e, 0x63, 0x72, 0x6f, 0x6e, - 0x5f, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x2d, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, - 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x6f, - 0x6e, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, - 0x00, 0x52, 0x0d, 0x63, 0x72, 0x6f, 0x6e, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, - 0x12, 0x53, 0x0a, 0x0d, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, - 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, - 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x6c, 0x69, 0x6e, 0x65, - 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0c, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x45, 0x78, - 0x65, 0x63, 0x75, 0x74, 0x65, 0x12, 0x56, 0x0a, 0x0e, 0x70, 0x75, 0x62, 0x73, 0x75, 0x62, 0x5f, - 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, + 0x6c, 0x69, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x48, 0x00, 0x52, 0x03, 0x6c, 0x6f, 0x67, 0x12, 0x3a, 0x0a, 0x04, 0x63, 0x61, 0x6c, 0x6c, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x2e, 0x76, + 0x31, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x04, 0x63, + 0x61, 0x6c, 0x6c, 0x12, 0x62, 0x0a, 0x12, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, + 0x74, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x31, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, + 0x74, 0x69, 0x6d, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x70, 0x6c, + 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x48, 0x00, 0x52, 0x11, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x12, 0x62, 0x0a, 0x12, 0x64, 0x65, 0x70, 0x6c, 0x6f, + 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, + 0x66, 0x74, 0x6c, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, + 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x11, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, + 0x6d, 0x65, 0x6e, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x12, 0x43, 0x0a, 0x07, 0x69, + 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x78, + 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x74, 0x69, 0x6d, + 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x07, 0x69, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, + 0x12, 0x56, 0x0a, 0x0e, 0x63, 0x72, 0x6f, 0x6e, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, + 0x65, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, + 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x6c, 0x69, 0x6e, + 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x6f, 0x6e, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, + 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0d, 0x63, 0x72, 0x6f, 0x6e, 0x53, + 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x12, 0x53, 0x0a, 0x0d, 0x61, 0x73, 0x79, 0x6e, + 0x63, 0x5f, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x2c, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, + 0x74, 0x69, 0x6d, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x73, 0x79, 0x6e, + 0x63, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, + 0x0c, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x12, 0x56, 0x0a, + 0x0e, 0x70, 0x75, 0x62, 0x73, 0x75, 0x62, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x18, + 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x2e, 0x76, + 0x31, 0x2e, 0x50, 0x75, 0x62, 0x53, 0x75, 0x62, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0d, 0x70, 0x75, 0x62, 0x73, 0x75, 0x62, 0x50, 0x75, + 0x62, 0x6c, 0x69, 0x73, 0x68, 0x12, 0x56, 0x0a, 0x0e, 0x70, 0x75, 0x62, 0x73, 0x75, 0x62, 0x5f, + 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x75, 0x62, 0x53, 0x75, 0x62, - 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0d, - 0x70, 0x75, 0x62, 0x73, 0x75, 0x62, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x12, 0x56, 0x0a, - 0x0e, 0x70, 0x75, 0x62, 0x73, 0x75, 0x62, 0x5f, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x18, - 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x78, 0x79, 0x7a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, - 0x6b, 0x2e, 0x66, 0x74, 0x6c, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x2e, 0x76, - 0x31, 0x2e, 0x50, 0x75, 0x62, 0x53, 0x75, 0x62, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x45, - 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0d, 0x70, 0x75, 0x62, 0x73, 0x75, 0x62, 0x43, 0x6f, - 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x42, 0x07, 0x0a, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2a, 0xa9, - 0x02, 0x0a, 0x09, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x16, - 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, - 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x45, 0x56, 0x45, 0x4e, - 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4c, 0x4f, 0x47, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, - 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, 0x41, 0x4c, 0x4c, 0x10, - 0x02, 0x12, 0x21, 0x0a, 0x1d, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, - 0x44, 0x45, 0x50, 0x4c, 0x4f, 0x59, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, - 0x45, 0x44, 0x10, 0x03, 0x12, 0x21, 0x0a, 0x1d, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, - 0x50, 0x45, 0x5f, 0x44, 0x45, 0x50, 0x4c, 0x4f, 0x59, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x55, 0x50, - 0x44, 0x41, 0x54, 0x45, 0x44, 0x10, 0x04, 0x12, 0x16, 0x0a, 0x12, 0x45, 0x56, 0x45, 0x4e, 0x54, - 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x49, 0x4e, 0x47, 0x52, 0x45, 0x53, 0x53, 0x10, 0x05, 0x12, - 0x1d, 0x0a, 0x19, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, 0x52, - 0x4f, 0x4e, 0x5f, 0x53, 0x43, 0x48, 0x45, 0x44, 0x55, 0x4c, 0x45, 0x44, 0x10, 0x06, 0x12, 0x1c, - 0x0a, 0x18, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x41, 0x53, 0x59, - 0x4e, 0x43, 0x5f, 0x45, 0x58, 0x45, 0x43, 0x55, 0x54, 0x45, 0x10, 0x07, 0x12, 0x1d, 0x0a, 0x19, - 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x55, 0x42, 0x53, 0x55, - 0x42, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x53, 0x48, 0x10, 0x08, 0x12, 0x1d, 0x0a, 0x19, 0x45, - 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x55, 0x42, 0x53, 0x55, 0x42, - 0x5f, 0x43, 0x4f, 0x4e, 0x53, 0x55, 0x4d, 0x45, 0x10, 0x09, 0x2a, 0x89, 0x01, 0x0a, 0x15, 0x41, - 0x73, 0x79, 0x6e, 0x63, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, - 0x54, 0x79, 0x70, 0x65, 0x12, 0x28, 0x0a, 0x24, 0x41, 0x53, 0x59, 0x4e, 0x43, 0x5f, 0x45, 0x58, - 0x45, 0x43, 0x55, 0x54, 0x45, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, - 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x21, - 0x0a, 0x1d, 0x41, 0x53, 0x59, 0x4e, 0x43, 0x5f, 0x45, 0x58, 0x45, 0x43, 0x55, 0x54, 0x45, 0x5f, - 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, 0x52, 0x4f, 0x4e, 0x10, - 0x01, 0x12, 0x23, 0x0a, 0x1f, 0x41, 0x53, 0x59, 0x4e, 0x43, 0x5f, 0x45, 0x58, 0x45, 0x43, 0x55, - 0x54, 0x45, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x55, - 0x42, 0x53, 0x55, 0x42, 0x10, 0x02, 0x2a, 0x8c, 0x01, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x4c, 0x65, - 0x76, 0x65, 0x6c, 0x12, 0x19, 0x0a, 0x15, 0x4c, 0x4f, 0x47, 0x5f, 0x4c, 0x45, 0x56, 0x45, 0x4c, - 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x13, - 0x0a, 0x0f, 0x4c, 0x4f, 0x47, 0x5f, 0x4c, 0x45, 0x56, 0x45, 0x4c, 0x5f, 0x54, 0x52, 0x41, 0x43, - 0x45, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x4c, 0x4f, 0x47, 0x5f, 0x4c, 0x45, 0x56, 0x45, 0x4c, - 0x5f, 0x44, 0x45, 0x42, 0x55, 0x47, 0x10, 0x05, 0x12, 0x12, 0x0a, 0x0e, 0x4c, 0x4f, 0x47, 0x5f, - 0x4c, 0x45, 0x56, 0x45, 0x4c, 0x5f, 0x49, 0x4e, 0x46, 0x4f, 0x10, 0x09, 0x12, 0x12, 0x0a, 0x0e, - 0x4c, 0x4f, 0x47, 0x5f, 0x4c, 0x45, 0x56, 0x45, 0x4c, 0x5f, 0x57, 0x41, 0x52, 0x4e, 0x10, 0x0d, - 0x12, 0x13, 0x0a, 0x0f, 0x4c, 0x4f, 0x47, 0x5f, 0x4c, 0x45, 0x56, 0x45, 0x4c, 0x5f, 0x45, 0x52, - 0x52, 0x4f, 0x52, 0x10, 0x11, 0x42, 0x52, 0x50, 0x01, 0x5a, 0x4e, 0x67, 0x69, 0x74, 0x68, 0x75, - 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x54, 0x42, 0x44, 0x35, 0x34, 0x35, 0x36, 0x36, 0x39, 0x37, - 0x35, 0x2f, 0x66, 0x74, 0x6c, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x2f, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x78, 0x79, 0x7a, 0x2f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2f, 0x66, - 0x74, 0x6c, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x74, - 0x69, 0x6d, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, + 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0d, + 0x70, 0x75, 0x62, 0x73, 0x75, 0x62, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x42, 0x07, 0x0a, + 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2a, 0xa9, 0x02, 0x0a, 0x09, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x54, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x16, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, + 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, + 0x12, 0x12, 0x0a, 0x0e, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4c, + 0x4f, 0x47, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, + 0x50, 0x45, 0x5f, 0x43, 0x41, 0x4c, 0x4c, 0x10, 0x02, 0x12, 0x21, 0x0a, 0x1d, 0x45, 0x56, 0x45, + 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x45, 0x50, 0x4c, 0x4f, 0x59, 0x4d, 0x45, + 0x4e, 0x54, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x44, 0x10, 0x03, 0x12, 0x21, 0x0a, 0x1d, + 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x45, 0x50, 0x4c, 0x4f, + 0x59, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x44, 0x10, 0x04, 0x12, + 0x16, 0x0a, 0x12, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x49, 0x4e, + 0x47, 0x52, 0x45, 0x53, 0x53, 0x10, 0x05, 0x12, 0x1d, 0x0a, 0x19, 0x45, 0x56, 0x45, 0x4e, 0x54, + 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, 0x52, 0x4f, 0x4e, 0x5f, 0x53, 0x43, 0x48, 0x45, 0x44, + 0x55, 0x4c, 0x45, 0x44, 0x10, 0x06, 0x12, 0x1c, 0x0a, 0x18, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, + 0x54, 0x59, 0x50, 0x45, 0x5f, 0x41, 0x53, 0x59, 0x4e, 0x43, 0x5f, 0x45, 0x58, 0x45, 0x43, 0x55, + 0x54, 0x45, 0x10, 0x07, 0x12, 0x1d, 0x0a, 0x19, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, + 0x50, 0x45, 0x5f, 0x50, 0x55, 0x42, 0x53, 0x55, 0x42, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x53, + 0x48, 0x10, 0x08, 0x12, 0x1d, 0x0a, 0x19, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, + 0x45, 0x5f, 0x50, 0x55, 0x42, 0x53, 0x55, 0x42, 0x5f, 0x43, 0x4f, 0x4e, 0x53, 0x55, 0x4d, 0x45, + 0x10, 0x09, 0x2a, 0x89, 0x01, 0x0a, 0x15, 0x41, 0x73, 0x79, 0x6e, 0x63, 0x45, 0x78, 0x65, 0x63, + 0x75, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x28, 0x0a, 0x24, + 0x41, 0x53, 0x59, 0x4e, 0x43, 0x5f, 0x45, 0x58, 0x45, 0x43, 0x55, 0x54, 0x45, 0x5f, 0x45, 0x56, + 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, + 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x21, 0x0a, 0x1d, 0x41, 0x53, 0x59, 0x4e, 0x43, 0x5f, + 0x45, 0x58, 0x45, 0x43, 0x55, 0x54, 0x45, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, + 0x50, 0x45, 0x5f, 0x43, 0x52, 0x4f, 0x4e, 0x10, 0x01, 0x12, 0x23, 0x0a, 0x1f, 0x41, 0x53, 0x59, + 0x4e, 0x43, 0x5f, 0x45, 0x58, 0x45, 0x43, 0x55, 0x54, 0x45, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, + 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x55, 0x42, 0x53, 0x55, 0x42, 0x10, 0x02, 0x2a, 0x8c, + 0x01, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x19, 0x0a, 0x15, 0x4c, + 0x4f, 0x47, 0x5f, 0x4c, 0x45, 0x56, 0x45, 0x4c, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, + 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x13, 0x0a, 0x0f, 0x4c, 0x4f, 0x47, 0x5f, 0x4c, 0x45, + 0x56, 0x45, 0x4c, 0x5f, 0x54, 0x52, 0x41, 0x43, 0x45, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x4c, + 0x4f, 0x47, 0x5f, 0x4c, 0x45, 0x56, 0x45, 0x4c, 0x5f, 0x44, 0x45, 0x42, 0x55, 0x47, 0x10, 0x05, + 0x12, 0x12, 0x0a, 0x0e, 0x4c, 0x4f, 0x47, 0x5f, 0x4c, 0x45, 0x56, 0x45, 0x4c, 0x5f, 0x49, 0x4e, + 0x46, 0x4f, 0x10, 0x09, 0x12, 0x12, 0x0a, 0x0e, 0x4c, 0x4f, 0x47, 0x5f, 0x4c, 0x45, 0x56, 0x45, + 0x4c, 0x5f, 0x57, 0x41, 0x52, 0x4e, 0x10, 0x0d, 0x12, 0x13, 0x0a, 0x0f, 0x4c, 0x4f, 0x47, 0x5f, + 0x4c, 0x45, 0x56, 0x45, 0x4c, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x11, 0x42, 0x52, 0x50, + 0x01, 0x5a, 0x4e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x54, 0x42, + 0x44, 0x35, 0x34, 0x35, 0x36, 0x36, 0x39, 0x37, 0x35, 0x2f, 0x66, 0x74, 0x6c, 0x2f, 0x62, 0x61, + 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x78, 0x79, 0x7a, + 0x2f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2f, 0x66, 0x74, 0x6c, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x6c, + 0x69, 0x6e, 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x74, 0x69, 0x6d, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x76, + 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1635,29 +1634,29 @@ var file_xyz_block_ftl_timeline_v1_event_proto_goTypes = []any{ (*durationpb.Duration)(nil), // 16: google.protobuf.Duration } var file_xyz_block_ftl_timeline_v1_event_proto_depIdxs = []int32{ - 14, // 0: xyz.block.ftl.timeline.v1.LogEvent.time_stamp:type_name -> google.protobuf.Timestamp + 14, // 0: xyz.block.ftl.timeline.v1.LogEvent.timestamp:type_name -> google.protobuf.Timestamp 13, // 1: xyz.block.ftl.timeline.v1.LogEvent.attributes:type_name -> xyz.block.ftl.timeline.v1.LogEvent.AttributesEntry - 14, // 2: xyz.block.ftl.timeline.v1.CallEvent.time_stamp:type_name -> google.protobuf.Timestamp + 14, // 2: xyz.block.ftl.timeline.v1.CallEvent.timestamp:type_name -> google.protobuf.Timestamp 15, // 3: xyz.block.ftl.timeline.v1.CallEvent.source_verb_ref:type_name -> xyz.block.ftl.schema.v1.Ref 15, // 4: xyz.block.ftl.timeline.v1.CallEvent.destination_verb_ref:type_name -> xyz.block.ftl.schema.v1.Ref 16, // 5: xyz.block.ftl.timeline.v1.CallEvent.duration:type_name -> google.protobuf.Duration 15, // 6: xyz.block.ftl.timeline.v1.IngressEvent.verb_ref:type_name -> xyz.block.ftl.schema.v1.Ref - 14, // 7: xyz.block.ftl.timeline.v1.IngressEvent.time_stamp:type_name -> google.protobuf.Timestamp + 14, // 7: xyz.block.ftl.timeline.v1.IngressEvent.timestamp:type_name -> google.protobuf.Timestamp 16, // 8: xyz.block.ftl.timeline.v1.IngressEvent.duration:type_name -> google.protobuf.Duration 15, // 9: xyz.block.ftl.timeline.v1.CronScheduledEvent.verb_ref:type_name -> xyz.block.ftl.schema.v1.Ref - 14, // 10: xyz.block.ftl.timeline.v1.CronScheduledEvent.time_stamp:type_name -> google.protobuf.Timestamp + 14, // 10: xyz.block.ftl.timeline.v1.CronScheduledEvent.timestamp:type_name -> google.protobuf.Timestamp 16, // 11: xyz.block.ftl.timeline.v1.CronScheduledEvent.duration:type_name -> google.protobuf.Duration 14, // 12: xyz.block.ftl.timeline.v1.CronScheduledEvent.scheduled_at:type_name -> google.protobuf.Timestamp 15, // 13: xyz.block.ftl.timeline.v1.AsyncExecuteEvent.verb_ref:type_name -> xyz.block.ftl.schema.v1.Ref - 14, // 14: xyz.block.ftl.timeline.v1.AsyncExecuteEvent.time_stamp:type_name -> google.protobuf.Timestamp + 14, // 14: xyz.block.ftl.timeline.v1.AsyncExecuteEvent.timestamp:type_name -> google.protobuf.Timestamp 16, // 15: xyz.block.ftl.timeline.v1.AsyncExecuteEvent.duration:type_name -> google.protobuf.Duration 1, // 16: xyz.block.ftl.timeline.v1.AsyncExecuteEvent.async_event_type:type_name -> xyz.block.ftl.timeline.v1.AsyncExecuteEventType 15, // 17: xyz.block.ftl.timeline.v1.PubSubPublishEvent.verb_ref:type_name -> xyz.block.ftl.schema.v1.Ref - 14, // 18: xyz.block.ftl.timeline.v1.PubSubPublishEvent.time_stamp:type_name -> google.protobuf.Timestamp + 14, // 18: xyz.block.ftl.timeline.v1.PubSubPublishEvent.timestamp:type_name -> google.protobuf.Timestamp 16, // 19: xyz.block.ftl.timeline.v1.PubSubPublishEvent.duration:type_name -> google.protobuf.Duration - 14, // 20: xyz.block.ftl.timeline.v1.PubSubConsumeEvent.time_stamp:type_name -> google.protobuf.Timestamp + 14, // 20: xyz.block.ftl.timeline.v1.PubSubConsumeEvent.timestamp:type_name -> google.protobuf.Timestamp 16, // 21: xyz.block.ftl.timeline.v1.PubSubConsumeEvent.duration:type_name -> google.protobuf.Duration - 14, // 22: xyz.block.ftl.timeline.v1.Event.time_stamp:type_name -> google.protobuf.Timestamp + 14, // 22: xyz.block.ftl.timeline.v1.Event.timestamp:type_name -> google.protobuf.Timestamp 3, // 23: xyz.block.ftl.timeline.v1.Event.log:type_name -> xyz.block.ftl.timeline.v1.LogEvent 4, // 24: xyz.block.ftl.timeline.v1.Event.call:type_name -> xyz.block.ftl.timeline.v1.CallEvent 5, // 25: xyz.block.ftl.timeline.v1.Event.deployment_created:type_name -> xyz.block.ftl.timeline.v1.DeploymentCreatedEvent diff --git a/backend/protos/xyz/block/ftl/timeline/v1/event.proto b/backend/protos/xyz/block/ftl/timeline/v1/event.proto index bb4d03deab..6174c0f9c3 100644 --- a/backend/protos/xyz/block/ftl/timeline/v1/event.proto +++ b/backend/protos/xyz/block/ftl/timeline/v1/event.proto @@ -40,7 +40,7 @@ enum LogLevel { message LogEvent { string deployment_key = 1; optional string request_key = 2; - google.protobuf.Timestamp time_stamp = 3; + google.protobuf.Timestamp timestamp = 3; int32 log_level = 4; map attributes = 5; string message = 6; @@ -51,7 +51,7 @@ message LogEvent { message CallEvent { optional string request_key = 1; string deployment_key = 2; - google.protobuf.Timestamp time_stamp = 3; + google.protobuf.Timestamp timestamp = 3; optional ftl.schema.v1.Ref source_verb_ref = 11; ftl.schema.v1.Ref destination_verb_ref = 12; google.protobuf.Duration duration = 6; @@ -84,7 +84,7 @@ message IngressEvent { string method = 4; string path = 5; int32 status_code = 7; - google.protobuf.Timestamp time_stamp = 8; + google.protobuf.Timestamp timestamp = 8; google.protobuf.Duration duration = 9; string request = 10; string request_header = 11; @@ -96,7 +96,7 @@ message IngressEvent { message CronScheduledEvent { string deployment_key = 1; ftl.schema.v1.Ref verb_ref = 2; - google.protobuf.Timestamp time_stamp = 3; + google.protobuf.Timestamp timestamp = 3; google.protobuf.Duration duration = 4; google.protobuf.Timestamp scheduled_at = 5; string schedule = 6; @@ -107,7 +107,7 @@ message AsyncExecuteEvent { string deployment_key = 1; optional string request_key = 2; ftl.schema.v1.Ref verb_ref = 3; - google.protobuf.Timestamp time_stamp = 4; + google.protobuf.Timestamp timestamp = 4; google.protobuf.Duration duration = 5; AsyncExecuteEventType async_event_type = 6; optional string error = 7; @@ -117,7 +117,7 @@ message PubSubPublishEvent { string deployment_key = 1; optional string request_key = 2; ftl.schema.v1.Ref verb_ref = 3; - google.protobuf.Timestamp time_stamp = 4; + google.protobuf.Timestamp timestamp = 4; google.protobuf.Duration duration = 5; string topic = 6; string request = 7; @@ -129,14 +129,14 @@ message PubSubConsumeEvent { optional string request_key = 2; optional string dest_verb_module = 3; optional string dest_verb_name = 4; - google.protobuf.Timestamp time_stamp = 5; + google.protobuf.Timestamp timestamp = 5; google.protobuf.Duration duration = 6; string topic = 7; optional string error = 8; } message Event { - google.protobuf.Timestamp time_stamp = 1; + google.protobuf.Timestamp timestamp = 1; // Unique ID for event. int64 id = 2; oneof entry { diff --git a/backend/timeline/events_async.go b/backend/timeline/events_async.go new file mode 100644 index 0000000000..7c139d86ee --- /dev/null +++ b/backend/timeline/events_async.go @@ -0,0 +1,64 @@ +package timeline + +import ( + "time" + + "github.com/alecthomas/types/optional" + "google.golang.org/protobuf/types/known/durationpb" + "google.golang.org/protobuf/types/known/timestamppb" + + schemapb "github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/schema/v1" + timelinepb "github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/timeline/v1" + "github.com/TBD54566975/ftl/internal/model" + "github.com/TBD54566975/ftl/internal/schema" +) + +type AsyncExecuteEventType string + +const ( + AsyncExecuteEventTypeUnkown AsyncExecuteEventType = "unknown" + AsyncExecuteEventTypeCron AsyncExecuteEventType = "cron" + AsyncExecuteEventTypePubSub AsyncExecuteEventType = "pubsub" +) + +func asyncExecuteEventTypeToProto(eventType AsyncExecuteEventType) timelinepb.AsyncExecuteEventType { + switch eventType { + case AsyncExecuteEventTypeCron: + return timelinepb.AsyncExecuteEventType_ASYNC_EXECUTE_EVENT_TYPE_CRON + case AsyncExecuteEventTypePubSub: + return timelinepb.AsyncExecuteEventType_ASYNC_EXECUTE_EVENT_TYPE_PUBSUB + case AsyncExecuteEventTypeUnkown: + return timelinepb.AsyncExecuteEventType_ASYNC_EXECUTE_EVENT_TYPE_UNSPECIFIED + + default: + panic("unknown async execute event type") + } +} + +type AsyncExecute struct { + DeploymentKey model.DeploymentKey + RequestKey optional.Option[string] + EventType AsyncExecuteEventType + Verb schema.Ref + Time time.Time + Error optional.Option[string] +} + +var _ Event = AsyncExecute{} + +func (AsyncExecute) clientEvent() {} +func (a AsyncExecute) ToReq() (*timelinepb.CreateEventRequest, error) { + return &timelinepb.CreateEventRequest{ + Entry: &timelinepb.CreateEventRequest_AsyncExecute{ + AsyncExecute: &timelinepb.AsyncExecuteEvent{ + DeploymentKey: a.DeploymentKey.String(), + RequestKey: a.RequestKey.Ptr(), + Timestamp: timestamppb.New(a.Time), + Error: a.Error.Ptr(), + Duration: durationpb.New(time.Since(a.Time)), + VerbRef: (&a.Verb).ToProto().(*schemapb.Ref), //nolint:forcetypeassert + AsyncEventType: asyncExecuteEventTypeToProto(a.EventType), + }, + }, + }, nil +} diff --git a/backend/timeline/events_call.go b/backend/timeline/events_call.go new file mode 100644 index 0000000000..a1a0768631 --- /dev/null +++ b/backend/timeline/events_call.go @@ -0,0 +1,68 @@ +package timeline + +import ( + "time" + + "github.com/alecthomas/types/optional" + "github.com/alecthomas/types/result" + "google.golang.org/protobuf/types/known/durationpb" + "google.golang.org/protobuf/types/known/timestamppb" + + schemapb "github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/schema/v1" + timelinepb "github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/timeline/v1" + ftlv1 "github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/v1" + "github.com/TBD54566975/ftl/internal/model" + "github.com/TBD54566975/ftl/internal/schema" +) + +type Call struct { + DeploymentKey model.DeploymentKey + RequestKey model.RequestKey + ParentRequestKey optional.Option[model.RequestKey] + StartTime time.Time + DestVerb *schema.Ref + Callers []*schema.Ref + Request *ftlv1.CallRequest + Response result.Result[*ftlv1.CallResponse] +} + +func (Call) clientEvent() {} +func (c Call) ToReq() (*timelinepb.CreateEventRequest, error) { + requestKey := c.RequestKey.String() + + var respError *string + var responseBody []byte + var stack *string + resp, err := c.Response.Result() + if err != nil { + errStr := err.Error() + respError = &errStr + } else { + responseBody = resp.GetBody() + if callError := resp.GetError(); callError != nil { + respError = optional.Some(callError.Message).Ptr() + stack = callError.Stack + } + } + var sourceVerb *schemapb.Ref + if len(c.Callers) > 0 { + sourceVerb = c.Callers[0].ToProto().(*schemapb.Ref) //nolint:forcetypeassert + } + + return &timelinepb.CreateEventRequest{ + Entry: &timelinepb.CreateEventRequest_Call{ + Call: &timelinepb.CallEvent{ + RequestKey: &requestKey, + DeploymentKey: c.DeploymentKey.String(), + Timestamp: timestamppb.New(c.StartTime), + Response: string(responseBody), + Error: respError, + SourceVerbRef: sourceVerb, + DestinationVerbRef: c.DestVerb.ToProto().(*schemapb.Ref), //nolint:forcetypeassert + Duration: durationpb.New(time.Since(c.StartTime)), + Request: string(c.Request.GetBody()), + Stack: stack, + }, + }, + }, nil +} diff --git a/backend/timeline/events_deployment.go b/backend/timeline/events_deployment.go new file mode 100644 index 0000000000..90a7f44222 --- /dev/null +++ b/backend/timeline/events_deployment.go @@ -0,0 +1,63 @@ +package timeline + +import ( + "time" + + "github.com/alecthomas/types/optional" + + timelinepb "github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/timeline/v1" + "github.com/TBD54566975/ftl/internal/model" +) + +type DeploymentCreated struct { + DeploymentKey model.DeploymentKey + Time time.Time + Language string + ModuleName string + MinReplicas int + ReplacedDeployment optional.Option[model.DeploymentKey] +} + +var _ Event = DeploymentCreated{} + +func (DeploymentCreated) clientEvent() {} +func (d DeploymentCreated) ToReq() (*timelinepb.CreateEventRequest, error) { + var replaced *string + if r, ok := d.ReplacedDeployment.Get(); ok { + repl := r.String() + replaced = &repl + } + return &timelinepb.CreateEventRequest{ + Entry: &timelinepb.CreateEventRequest_DeploymentCreated{ + DeploymentCreated: &timelinepb.DeploymentCreatedEvent{ + Key: d.DeploymentKey.String(), + Language: d.Language, + ModuleName: d.ModuleName, + MinReplicas: int32(d.MinReplicas), + Replaced: replaced, + }, + }, + }, nil +} + +type DeploymentUpdated struct { + DeploymentKey model.DeploymentKey + Time time.Time + MinReplicas int + PrevMinReplicas int +} + +var _ Event = DeploymentUpdated{} + +func (DeploymentUpdated) clientEvent() {} +func (d DeploymentUpdated) ToReq() (*timelinepb.CreateEventRequest, error) { + return &timelinepb.CreateEventRequest{ + Entry: &timelinepb.CreateEventRequest_DeploymentUpdated{ + DeploymentUpdated: &timelinepb.DeploymentUpdatedEvent{ + Key: d.DeploymentKey.String(), + MinReplicas: int32(d.MinReplicas), + PrevMinReplicas: int32(d.PrevMinReplicas), + }, + }, + }, nil +} diff --git a/backend/timeline/events_ingress.go b/backend/timeline/events_ingress.go new file mode 100644 index 0000000000..98dd5863bc --- /dev/null +++ b/backend/timeline/events_ingress.go @@ -0,0 +1,79 @@ +package timeline + +import ( + "encoding/json" + "fmt" + "net/http" + "time" + + "github.com/alecthomas/types/optional" + "google.golang.org/protobuf/types/known/durationpb" + "google.golang.org/protobuf/types/known/timestamppb" + + schemapb "github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/schema/v1" + timelinepb "github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/timeline/v1" + "github.com/TBD54566975/ftl/internal/model" + "github.com/TBD54566975/ftl/internal/schema" +) + +type Ingress struct { + DeploymentKey model.DeploymentKey + RequestKey model.RequestKey + StartTime time.Time + Verb *schema.Ref + RequestMethod string + RequestPath string + RequestHeaders http.Header + ResponseStatus int + ResponseHeaders http.Header + RequestBody []byte + ResponseBody []byte + Error optional.Option[string] +} + +var _ Event = Ingress{} + +func (Ingress) clientEvent() {} +func (i Ingress) ToReq() (*timelinepb.CreateEventRequest, error) { + requestKey := i.RequestKey.String() + + requestBody := i.RequestBody + if len(requestBody) == 0 { + requestBody = []byte("{}") + } + + responseBody := i.ResponseBody + if len(responseBody) == 0 { + responseBody = []byte("{}") + } + + reqHeaderBytes, err := json.Marshal(i.RequestHeaders) + if err != nil { + return nil, fmt.Errorf("failed to marshal request header: %w", err) + } + + respHeaderBytes, err := json.Marshal(i.ResponseHeaders) + if err != nil { + return nil, fmt.Errorf("failed to marshal response header: %w", err) + } + + return &timelinepb.CreateEventRequest{ + Entry: &timelinepb.CreateEventRequest_Ingress{ + Ingress: &timelinepb.IngressEvent{ + DeploymentKey: i.DeploymentKey.String(), + RequestKey: &requestKey, + Timestamp: timestamppb.New(i.StartTime), + VerbRef: i.Verb.ToProto().(*schemapb.Ref), //nolint:forcetypeassert + Method: i.RequestMethod, + Path: i.RequestPath, + StatusCode: int32(i.ResponseStatus), + Duration: durationpb.New(time.Since(i.StartTime)), + Request: string(requestBody), + RequestHeader: string(reqHeaderBytes), + Response: string(responseBody), + ResponseHeader: string(respHeaderBytes), + Error: i.Error.Ptr(), + }, + }, + }, nil +} diff --git a/backend/timeline/events_log.go b/backend/timeline/events_log.go new file mode 100644 index 0000000000..6ab67af8d6 --- /dev/null +++ b/backend/timeline/events_log.go @@ -0,0 +1,45 @@ +package timeline + +import ( + "time" + + "github.com/alecthomas/types/optional" + "google.golang.org/protobuf/types/known/timestamppb" + + timelinepb "github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/timeline/v1" + "github.com/TBD54566975/ftl/internal/model" +) + +type Log struct { + DeploymentKey model.DeploymentKey + RequestKey optional.Option[model.RequestKey] + Time time.Time + Level int32 + Attributes map[string]string + Message string + Error optional.Option[string] +} + +var _ Event = Log{} + +func (Log) clientEvent() {} +func (l Log) ToReq() (*timelinepb.CreateEventRequest, error) { + var requestKey *string + if r, ok := l.RequestKey.Get(); ok { + key := r.String() + requestKey = &key + } + return &timelinepb.CreateEventRequest{ + Entry: &timelinepb.CreateEventRequest_Log{ + Log: &timelinepb.LogEvent{ + DeploymentKey: l.DeploymentKey.String(), + RequestKey: requestKey, + Timestamp: timestamppb.New(l.Time), + LogLevel: l.Level, + Attributes: l.Attributes, + Message: l.Message, + Error: l.Error.Ptr(), + }, + }, + }, nil +} diff --git a/backend/timeline/events_pubsub_consume.go b/backend/timeline/events_pubsub_consume.go new file mode 100644 index 0000000000..af7a1aeecf --- /dev/null +++ b/backend/timeline/events_pubsub_consume.go @@ -0,0 +1,47 @@ +package timeline + +import ( + "time" + + "github.com/alecthomas/types/optional" + "google.golang.org/protobuf/types/known/durationpb" + "google.golang.org/protobuf/types/known/timestamppb" + + timelinepb "github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/timeline/v1" + "github.com/TBD54566975/ftl/internal/model" + "github.com/TBD54566975/ftl/internal/schema" +) + +type PubSubConsume struct { + DeploymentKey model.DeploymentKey + RequestKey optional.Option[string] + Time time.Time + DestVerb optional.Option[schema.RefKey] + Topic string + Error optional.Option[string] +} + +var _ Event = PubSubConsume{} + +func (PubSubConsume) clientEvent() {} +func (p PubSubConsume) ToReq() (*timelinepb.CreateEventRequest, error) { + var destModule, destVerb *string + if ref, ok := p.DestVerb.Get(); ok { + destModule = &ref.Module + destVerb = &ref.Name + } + return &timelinepb.CreateEventRequest{ + Entry: &timelinepb.CreateEventRequest_PubsubConsume{ + PubsubConsume: &timelinepb.PubSubConsumeEvent{ + DeploymentKey: p.DeploymentKey.String(), + RequestKey: p.RequestKey.Ptr(), + Timestamp: timestamppb.New(p.Time), + Topic: p.Topic, + Error: p.Error.Ptr(), + DestVerbModule: destModule, + DestVerbName: destVerb, + Duration: durationpb.New(time.Since(p.Time)), + }, + }, + }, nil +} diff --git a/backend/timeline/events_pubsub_publish.go b/backend/timeline/events_pubsub_publish.go new file mode 100644 index 0000000000..60088bc621 --- /dev/null +++ b/backend/timeline/events_pubsub_publish.go @@ -0,0 +1,46 @@ +package timeline + +import ( + "time" + + "github.com/alecthomas/types/optional" + "google.golang.org/protobuf/types/known/durationpb" + "google.golang.org/protobuf/types/known/timestamppb" + + deployment "github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/deployment/v1" + schemapb "github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/schema/v1" + timelinepb "github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/timeline/v1" + "github.com/TBD54566975/ftl/internal/model" + "github.com/TBD54566975/ftl/internal/schema" +) + +type PubSubPublish struct { + DeploymentKey model.DeploymentKey + RequestKey optional.Option[string] + Time time.Time + SourceVerb schema.Ref + Topic string + // Should this just be request body? + Request *deployment.PublishEventRequest + Error optional.Option[string] +} + +var _ Event = PubSubPublish{} + +func (PubSubPublish) clientEvent() {} +func (p PubSubPublish) ToReq() (*timelinepb.CreateEventRequest, error) { + return &timelinepb.CreateEventRequest{ + Entry: &timelinepb.CreateEventRequest_PubsubPublish{ + PubsubPublish: &timelinepb.PubSubPublishEvent{ + DeploymentKey: p.DeploymentKey.String(), + RequestKey: p.RequestKey.Ptr(), + VerbRef: (&p.SourceVerb).ToProto().(*schemapb.Ref), //nolint:forcetypeassert + Timestamp: timestamppb.New(p.Time), + Duration: durationpb.New(time.Since(p.Time)), + Topic: p.Topic, + Request: string(p.Request.Body), + Error: p.Error.Ptr(), + }, + }, + }, nil +} diff --git a/backend/timeline/filters.go b/backend/timeline/filters.go index 718215a02a..c5fff0ec3a 100644 --- a/backend/timeline/filters.go +++ b/backend/timeline/filters.go @@ -191,10 +191,10 @@ func FilterTypes(filters ...*timelinepb.GetTimelineRequest_EventTypeFilter) Time // FilterTimeRange filters events between the given times, inclusive. func FilterTimeRange(filter *timelinepb.GetTimelineRequest_TimeFilter) TimelineFilter { return func(event *timelinepb.Event) bool { - if filter.NewerThan != nil && event.TimeStamp.AsTime().Before(filter.NewerThan.AsTime()) { + if filter.NewerThan != nil && event.Timestamp.AsTime().Before(filter.NewerThan.AsTime()) { return false } - if filter.OlderThan != nil && event.TimeStamp.AsTime().After(filter.OlderThan.AsTime()) { + if filter.OlderThan != nil && event.Timestamp.AsTime().After(filter.OlderThan.AsTime()) { return false } return true diff --git a/backend/timeline/publish.go b/backend/timeline/publish.go new file mode 100644 index 0000000000..5c20fc7298 --- /dev/null +++ b/backend/timeline/publish.go @@ -0,0 +1,31 @@ +package timeline + +import ( + "context" + + "connectrpc.com/connect" + + timelinepb "github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/timeline/v1" + "github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/timeline/v1/timelinev1connect" + "github.com/TBD54566975/ftl/internal/log" + "github.com/TBD54566975/ftl/internal/rpc" +) + +//go:sumtype +type Event interface { + ToReq() (*timelinepb.CreateEventRequest, error) + clientEvent() +} + +func Publish(ctx context.Context, event Event) { + client := rpc.ClientFromContext[timelinev1connect.TimelineServiceClient](ctx) + req, err := event.ToReq() + if err != nil { + log.FromContext(ctx).Warnf("failed to create request to publish %T event: %v", event, err) + return + } + _, err = client.CreateEvent(ctx, connect.NewRequest(req)) + if err != nil { + log.FromContext(ctx).Warnf("failed to publish %T event: %v", event, err) + } +} diff --git a/backend/timeline/service.go b/backend/timeline/service.go index 5be3cf4814..48ed53a24c 100644 --- a/backend/timeline/service.go +++ b/backend/timeline/service.go @@ -40,7 +40,10 @@ func Start(ctx context.Context, config Config, schemaEventSource schemaeventsour config.SetDefaults() logger := log.FromContext(ctx).Scope("timeline") - svc := &service{} + svc := &service{ + events: make([]*timelinepb.Event, 0), + nextID: 0, + } logger.Debugf("Timeline service listening on: %s", config.Bind) err := rpc.Serve(ctx, config.Bind, @@ -62,7 +65,7 @@ func (s *service) CreateEvent(ctx context.Context, req *connect.Request[timeline event := &timelinepb.Event{ Id: int64(s.nextID), - TimeStamp: timestamppb.Now(), + Timestamp: timestamppb.Now(), } switch entry := req.Msg.Entry.(type) { case *timelinepb.CreateEventRequest_Log: @@ -134,7 +137,7 @@ func (s *service) GetTimeline(ctx context.Context, req *connect.Request[timeline _, didNotMatchAFilter := slices.Find(filters, func(filter TimelineFilter) bool { return !filter(event) }) - for didNotMatchAFilter { + if didNotMatchAFilter { continue } results = append(results, s.events[i]) @@ -162,14 +165,19 @@ func (s *service) DeleteOldEvents(ctx context.Context, req *connect.Request[time } filtered := []*timelinepb.Event{} + deleted := int64(0) for _, event := range s.events { _, didNotMatchAFilter := slices.Find(deletionFilters, func(filter TimelineFilter) bool { return !filter(event) }) if didNotMatchAFilter { filtered = append(filtered, event) + } else { + deleted++ } } s.events = filtered - return connect.NewResponse(&timelinepb.DeleteOldEventsResponse{}), nil + return connect.NewResponse(&timelinepb.DeleteOldEventsResponse{ + DeletedCount: deleted, + }), nil } diff --git a/frontend/console/src/features/timeline/TimelineEventList.tsx b/frontend/console/src/features/timeline/TimelineEventList.tsx index 512c14094c..a41638eb80 100644 --- a/frontend/console/src/features/timeline/TimelineEventList.tsx +++ b/frontend/console/src/features/timeline/TimelineEventList.tsx @@ -60,7 +60,7 @@ export const TimelineEventList = ({ events, selectedEventId, handleEntryClicked - {formatTimestampShort(entry.timeStamp)} + {formatTimestampShort(entry.timestamp)} {deploymentKey(entry)} diff --git a/frontend/console/src/features/timeline/details/TimelineDetailsHeader.tsx b/frontend/console/src/features/timeline/details/TimelineDetailsHeader.tsx index 5f3adfad59..4fe259d1f5 100644 --- a/frontend/console/src/features/timeline/details/TimelineDetailsHeader.tsx +++ b/frontend/console/src/features/timeline/details/TimelineDetailsHeader.tsx @@ -19,8 +19,8 @@ export const TimelineDetailsHeader = ({ event }: { event: Event }) => {
{eventBadge(event)} -
diff --git a/frontend/console/src/features/traces/traces.utils.ts b/frontend/console/src/features/traces/traces.utils.ts index 95a7643fbd..f5dffb13a0 100644 --- a/frontend/console/src/features/traces/traces.utils.ts +++ b/frontend/console/src/features/traces/traces.utils.ts @@ -3,11 +3,11 @@ import type { Event } from '../../protos/xyz/block/ftl/timeline/v1/event_pb' import { compareTimestamps, durationToMillis } from '../../utils' export const eventBarLeftOffsetPercentage = (event: Event, requestStartTime: number, requestDurationMs: number) => { - if (!event.timeStamp) { + if (!event.timestamp) { return 0 } - const offsetInMillis = event.timeStamp.toDate().getTime() - requestStartTime + const offsetInMillis = event.timestamp.toDate().getTime() - requestStartTime return (offsetInMillis / requestDurationMs) * 100 } @@ -33,7 +33,7 @@ export const groupEventsByRequestKey = (events: Event[]): Record compareTimestamps(a.timeStamp, b.timeStamp)) + acc[requestKey].sort((a, b) => compareTimestamps(a.timestamp, b.timestamp)) return acc }, {}) @@ -41,7 +41,7 @@ export const groupEventsByRequestKey = (events: Event[]): Record { const traceEvents = events.map((event) => event.entry.value as TraceEvent) - return Math.min(...traceEvents.map((event) => event.timeStamp?.toDate().getTime() ?? 0)) + return Math.min(...traceEvents.map((event) => event.timestamp?.toDate().getTime() ?? 0)) } export const totalDurationForRequest = (events: Event[]): number => { @@ -49,7 +49,7 @@ export const totalDurationForRequest = (events: Event[]): number => { const requestEndTime = Math.max( ...traceEvents.map((event) => { const eventDuration = event.duration ? durationToMillis(event.duration) : 0 - return (event.timeStamp?.toDate().getTime() ?? 0) + eventDuration + return (event.timestamp?.toDate().getTime() ?? 0) + eventDuration }), ) return requestEndTime - requestStartTime(events) diff --git a/frontend/console/src/protos/xyz/block/ftl/timeline/v1/event_pb.ts b/frontend/console/src/protos/xyz/block/ftl/timeline/v1/event_pb.ts index 526a2f1d07..92cbaf8dea 100644 --- a/frontend/console/src/protos/xyz/block/ftl/timeline/v1/event_pb.ts +++ b/frontend/console/src/protos/xyz/block/ftl/timeline/v1/event_pb.ts @@ -160,9 +160,9 @@ export class LogEvent extends Message { requestKey?: string; /** - * @generated from field: google.protobuf.Timestamp time_stamp = 3; + * @generated from field: google.protobuf.Timestamp timestamp = 3; */ - timeStamp?: Timestamp; + timestamp?: Timestamp; /** * @generated from field: int32 log_level = 4; @@ -199,7 +199,7 @@ export class LogEvent extends Message { static readonly fields: FieldList = proto3.util.newFieldList(() => [ { no: 1, name: "deployment_key", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 2, name: "request_key", kind: "scalar", T: 9 /* ScalarType.STRING */, opt: true }, - { no: 3, name: "time_stamp", kind: "message", T: Timestamp }, + { no: 3, name: "timestamp", kind: "message", T: Timestamp }, { no: 4, name: "log_level", kind: "scalar", T: 5 /* ScalarType.INT32 */ }, { no: 5, name: "attributes", kind: "map", K: 9 /* ScalarType.STRING */, V: {kind: "scalar", T: 9 /* ScalarType.STRING */} }, { no: 6, name: "message", kind: "scalar", T: 9 /* ScalarType.STRING */ }, @@ -239,9 +239,9 @@ export class CallEvent extends Message { deploymentKey = ""; /** - * @generated from field: google.protobuf.Timestamp time_stamp = 3; + * @generated from field: google.protobuf.Timestamp timestamp = 3; */ - timeStamp?: Timestamp; + timestamp?: Timestamp; /** * @generated from field: optional xyz.block.ftl.schema.v1.Ref source_verb_ref = 11; @@ -288,7 +288,7 @@ export class CallEvent extends Message { static readonly fields: FieldList = proto3.util.newFieldList(() => [ { no: 1, name: "request_key", kind: "scalar", T: 9 /* ScalarType.STRING */, opt: true }, { no: 2, name: "deployment_key", kind: "scalar", T: 9 /* ScalarType.STRING */ }, - { no: 3, name: "time_stamp", kind: "message", T: Timestamp }, + { no: 3, name: "timestamp", kind: "message", T: Timestamp }, { no: 11, name: "source_verb_ref", kind: "message", T: Ref, opt: true }, { no: 12, name: "destination_verb_ref", kind: "message", T: Ref }, { no: 6, name: "duration", kind: "message", T: Duration }, @@ -460,9 +460,9 @@ export class IngressEvent extends Message { statusCode = 0; /** - * @generated from field: google.protobuf.Timestamp time_stamp = 8; + * @generated from field: google.protobuf.Timestamp timestamp = 8; */ - timeStamp?: Timestamp; + timestamp?: Timestamp; /** * @generated from field: google.protobuf.Duration duration = 9; @@ -508,7 +508,7 @@ export class IngressEvent extends Message { { no: 4, name: "method", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 5, name: "path", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 7, name: "status_code", kind: "scalar", T: 5 /* ScalarType.INT32 */ }, - { no: 8, name: "time_stamp", kind: "message", T: Timestamp }, + { no: 8, name: "timestamp", kind: "message", T: Timestamp }, { no: 9, name: "duration", kind: "message", T: Duration }, { no: 10, name: "request", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 11, name: "request_header", kind: "scalar", T: 9 /* ScalarType.STRING */ }, @@ -549,9 +549,9 @@ export class CronScheduledEvent extends Message { verbRef?: Ref; /** - * @generated from field: google.protobuf.Timestamp time_stamp = 3; + * @generated from field: google.protobuf.Timestamp timestamp = 3; */ - timeStamp?: Timestamp; + timestamp?: Timestamp; /** * @generated from field: google.protobuf.Duration duration = 4; @@ -583,7 +583,7 @@ export class CronScheduledEvent extends Message { static readonly fields: FieldList = proto3.util.newFieldList(() => [ { no: 1, name: "deployment_key", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 2, name: "verb_ref", kind: "message", T: Ref }, - { no: 3, name: "time_stamp", kind: "message", T: Timestamp }, + { no: 3, name: "timestamp", kind: "message", T: Timestamp }, { no: 4, name: "duration", kind: "message", T: Duration }, { no: 5, name: "scheduled_at", kind: "message", T: Timestamp }, { no: 6, name: "schedule", kind: "scalar", T: 9 /* ScalarType.STRING */ }, @@ -627,9 +627,9 @@ export class AsyncExecuteEvent extends Message { verbRef?: Ref; /** - * @generated from field: google.protobuf.Timestamp time_stamp = 4; + * @generated from field: google.protobuf.Timestamp timestamp = 4; */ - timeStamp?: Timestamp; + timestamp?: Timestamp; /** * @generated from field: google.protobuf.Duration duration = 5; @@ -657,7 +657,7 @@ export class AsyncExecuteEvent extends Message { { no: 1, name: "deployment_key", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 2, name: "request_key", kind: "scalar", T: 9 /* ScalarType.STRING */, opt: true }, { no: 3, name: "verb_ref", kind: "message", T: Ref }, - { no: 4, name: "time_stamp", kind: "message", T: Timestamp }, + { no: 4, name: "timestamp", kind: "message", T: Timestamp }, { no: 5, name: "duration", kind: "message", T: Duration }, { no: 6, name: "async_event_type", kind: "enum", T: proto3.getEnumType(AsyncExecuteEventType) }, { no: 7, name: "error", kind: "scalar", T: 9 /* ScalarType.STRING */, opt: true }, @@ -700,9 +700,9 @@ export class PubSubPublishEvent extends Message { verbRef?: Ref; /** - * @generated from field: google.protobuf.Timestamp time_stamp = 4; + * @generated from field: google.protobuf.Timestamp timestamp = 4; */ - timeStamp?: Timestamp; + timestamp?: Timestamp; /** * @generated from field: google.protobuf.Duration duration = 5; @@ -735,7 +735,7 @@ export class PubSubPublishEvent extends Message { { no: 1, name: "deployment_key", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 2, name: "request_key", kind: "scalar", T: 9 /* ScalarType.STRING */, opt: true }, { no: 3, name: "verb_ref", kind: "message", T: Ref }, - { no: 4, name: "time_stamp", kind: "message", T: Timestamp }, + { no: 4, name: "timestamp", kind: "message", T: Timestamp }, { no: 5, name: "duration", kind: "message", T: Duration }, { no: 6, name: "topic", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 7, name: "request", kind: "scalar", T: 9 /* ScalarType.STRING */ }, @@ -784,9 +784,9 @@ export class PubSubConsumeEvent extends Message { destVerbName?: string; /** - * @generated from field: google.protobuf.Timestamp time_stamp = 5; + * @generated from field: google.protobuf.Timestamp timestamp = 5; */ - timeStamp?: Timestamp; + timestamp?: Timestamp; /** * @generated from field: google.protobuf.Duration duration = 6; @@ -815,7 +815,7 @@ export class PubSubConsumeEvent extends Message { { no: 2, name: "request_key", kind: "scalar", T: 9 /* ScalarType.STRING */, opt: true }, { no: 3, name: "dest_verb_module", kind: "scalar", T: 9 /* ScalarType.STRING */, opt: true }, { no: 4, name: "dest_verb_name", kind: "scalar", T: 9 /* ScalarType.STRING */, opt: true }, - { no: 5, name: "time_stamp", kind: "message", T: Timestamp }, + { no: 5, name: "timestamp", kind: "message", T: Timestamp }, { no: 6, name: "duration", kind: "message", T: Duration }, { no: 7, name: "topic", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 8, name: "error", kind: "scalar", T: 9 /* ScalarType.STRING */, opt: true }, @@ -843,9 +843,9 @@ export class PubSubConsumeEvent extends Message { */ export class Event extends Message { /** - * @generated from field: google.protobuf.Timestamp time_stamp = 1; + * @generated from field: google.protobuf.Timestamp timestamp = 1; */ - timeStamp?: Timestamp; + timestamp?: Timestamp; /** * Unique ID for event. @@ -921,7 +921,7 @@ export class Event extends Message { static readonly runtime: typeof proto3 = proto3; static readonly typeName = "xyz.block.ftl.timeline.v1.Event"; static readonly fields: FieldList = proto3.util.newFieldList(() => [ - { no: 1, name: "time_stamp", kind: "message", T: Timestamp }, + { no: 1, name: "timestamp", kind: "message", T: Timestamp }, { no: 2, name: "id", kind: "scalar", T: 3 /* ScalarType.INT64 */ }, { no: 3, name: "log", kind: "message", T: LogEvent, oneof: "entry" }, { no: 4, name: "call", kind: "message", T: CallEvent, oneof: "entry" }, diff --git a/python-runtime/ftl/src/ftl/protos/xyz/block/ftl/timeline/v1/event_pb2.py b/python-runtime/ftl/src/ftl/protos/xyz/block/ftl/timeline/v1/event_pb2.py index 61fdf511f7..498ce32a32 100644 --- a/python-runtime/ftl/src/ftl/protos/xyz/block/ftl/timeline/v1/event_pb2.py +++ b/python-runtime/ftl/src/ftl/protos/xyz/block/ftl/timeline/v1/event_pb2.py @@ -27,7 +27,7 @@ from xyz.block.ftl.schema.v1 import schema_pb2 as xyz_dot_block_dot_ftl_dot_schema_dot_v1_dot_schema__pb2 -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n%xyz/block/ftl/timeline/v1/event.proto\x12\x19xyz.block.ftl.timeline.v1\x1a\x1egoogle/protobuf/duration.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a$xyz/block/ftl/schema/v1/schema.proto\"\xb7\x03\n\x08LogEvent\x12%\n\x0e\x64\x65ployment_key\x18\x01 \x01(\tR\rdeploymentKey\x12$\n\x0brequest_key\x18\x02 \x01(\tH\x00R\nrequestKey\x88\x01\x01\x12\x39\n\ntime_stamp\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.TimestampR\ttimeStamp\x12\x1b\n\tlog_level\x18\x04 \x01(\x05R\x08logLevel\x12S\n\nattributes\x18\x05 \x03(\x0b\x32\x33.xyz.block.ftl.timeline.v1.LogEvent.AttributesEntryR\nattributes\x12\x18\n\x07message\x18\x06 \x01(\tR\x07message\x12\x19\n\x05\x65rror\x18\x07 \x01(\tH\x01R\x05\x65rror\x88\x01\x01\x12\x19\n\x05stack\x18\x08 \x01(\tH\x02R\x05stack\x88\x01\x01\x1a=\n\x0f\x41ttributesEntry\x12\x10\n\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n\x05value\x18\x02 \x01(\tR\x05value:\x02\x38\x01\x42\x0e\n\x0c_request_keyB\x08\n\x06_errorB\x08\n\x06_stack\"\x95\x04\n\tCallEvent\x12$\n\x0brequest_key\x18\x01 \x01(\tH\x00R\nrequestKey\x88\x01\x01\x12%\n\x0e\x64\x65ployment_key\x18\x02 \x01(\tR\rdeploymentKey\x12\x39\n\ntime_stamp\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.TimestampR\ttimeStamp\x12I\n\x0fsource_verb_ref\x18\x0b \x01(\x0b\x32\x1c.xyz.block.ftl.schema.v1.RefH\x01R\rsourceVerbRef\x88\x01\x01\x12N\n\x14\x64\x65stination_verb_ref\x18\x0c \x01(\x0b\x32\x1c.xyz.block.ftl.schema.v1.RefR\x12\x64\x65stinationVerbRef\x12\x35\n\x08\x64uration\x18\x06 \x01(\x0b\x32\x19.google.protobuf.DurationR\x08\x64uration\x12\x18\n\x07request\x18\x07 \x01(\tR\x07request\x12\x1a\n\x08response\x18\x08 \x01(\tR\x08response\x12\x19\n\x05\x65rror\x18\t \x01(\tH\x02R\x05\x65rror\x88\x01\x01\x12\x19\n\x05stack\x18\n \x01(\tH\x03R\x05stack\x88\x01\x01\x42\x0e\n\x0c_request_keyB\x12\n\x10_source_verb_refB\x08\n\x06_errorB\x08\n\x06_stackJ\x04\x08\x04\x10\x05J\x04\x08\x05\x10\x06\"\xb8\x01\n\x16\x44\x65ploymentCreatedEvent\x12\x10\n\x03key\x18\x01 \x01(\tR\x03key\x12\x1a\n\x08language\x18\x02 \x01(\tR\x08language\x12\x1f\n\x0bmodule_name\x18\x03 \x01(\tR\nmoduleName\x12!\n\x0cmin_replicas\x18\x04 \x01(\x05R\x0bminReplicas\x12\x1f\n\x08replaced\x18\x05 \x01(\tH\x00R\x08replaced\x88\x01\x01\x42\x0b\n\t_replaced\"y\n\x16\x44\x65ploymentUpdatedEvent\x12\x10\n\x03key\x18\x01 \x01(\tR\x03key\x12!\n\x0cmin_replicas\x18\x02 \x01(\x05R\x0bminReplicas\x12*\n\x11prev_min_replicas\x18\x03 \x01(\x05R\x0fprevMinReplicas\"\x8e\x04\n\x0cIngressEvent\x12%\n\x0e\x64\x65ployment_key\x18\x01 \x01(\tR\rdeploymentKey\x12$\n\x0brequest_key\x18\x02 \x01(\tH\x00R\nrequestKey\x88\x01\x01\x12\x37\n\x08verb_ref\x18\x03 \x01(\x0b\x32\x1c.xyz.block.ftl.schema.v1.RefR\x07verbRef\x12\x16\n\x06method\x18\x04 \x01(\tR\x06method\x12\x12\n\x04path\x18\x05 \x01(\tR\x04path\x12\x1f\n\x0bstatus_code\x18\x07 \x01(\x05R\nstatusCode\x12\x39\n\ntime_stamp\x18\x08 \x01(\x0b\x32\x1a.google.protobuf.TimestampR\ttimeStamp\x12\x35\n\x08\x64uration\x18\t \x01(\x0b\x32\x19.google.protobuf.DurationR\x08\x64uration\x12\x18\n\x07request\x18\n \x01(\tR\x07request\x12%\n\x0erequest_header\x18\x0b \x01(\tR\rrequestHeader\x12\x1a\n\x08response\x18\x0c \x01(\tR\x08response\x12\'\n\x0fresponse_header\x18\r \x01(\tR\x0eresponseHeader\x12\x19\n\x05\x65rror\x18\x0e \x01(\tH\x01R\x05\x65rror\x88\x01\x01\x42\x0e\n\x0c_request_keyB\x08\n\x06_error\"\xe6\x02\n\x12\x43ronScheduledEvent\x12%\n\x0e\x64\x65ployment_key\x18\x01 \x01(\tR\rdeploymentKey\x12\x37\n\x08verb_ref\x18\x02 \x01(\x0b\x32\x1c.xyz.block.ftl.schema.v1.RefR\x07verbRef\x12\x39\n\ntime_stamp\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.TimestampR\ttimeStamp\x12\x35\n\x08\x64uration\x18\x04 \x01(\x0b\x32\x19.google.protobuf.DurationR\x08\x64uration\x12=\n\x0cscheduled_at\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.TimestampR\x0bscheduledAt\x12\x1a\n\x08schedule\x18\x06 \x01(\tR\x08schedule\x12\x19\n\x05\x65rror\x18\x07 \x01(\tH\x00R\x05\x65rror\x88\x01\x01\x42\x08\n\x06_error\"\x9c\x03\n\x11\x41syncExecuteEvent\x12%\n\x0e\x64\x65ployment_key\x18\x01 \x01(\tR\rdeploymentKey\x12$\n\x0brequest_key\x18\x02 \x01(\tH\x00R\nrequestKey\x88\x01\x01\x12\x37\n\x08verb_ref\x18\x03 \x01(\x0b\x32\x1c.xyz.block.ftl.schema.v1.RefR\x07verbRef\x12\x39\n\ntime_stamp\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.TimestampR\ttimeStamp\x12\x35\n\x08\x64uration\x18\x05 \x01(\x0b\x32\x19.google.protobuf.DurationR\x08\x64uration\x12Z\n\x10\x61sync_event_type\x18\x06 \x01(\x0e\x32\x30.xyz.block.ftl.timeline.v1.AsyncExecuteEventTypeR\x0e\x61syncEventType\x12\x19\n\x05\x65rror\x18\x07 \x01(\tH\x01R\x05\x65rror\x88\x01\x01\x42\x0e\n\x0c_request_keyB\x08\n\x06_error\"\xf1\x02\n\x12PubSubPublishEvent\x12%\n\x0e\x64\x65ployment_key\x18\x01 \x01(\tR\rdeploymentKey\x12$\n\x0brequest_key\x18\x02 \x01(\tH\x00R\nrequestKey\x88\x01\x01\x12\x37\n\x08verb_ref\x18\x03 \x01(\x0b\x32\x1c.xyz.block.ftl.schema.v1.RefR\x07verbRef\x12\x39\n\ntime_stamp\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.TimestampR\ttimeStamp\x12\x35\n\x08\x64uration\x18\x05 \x01(\x0b\x32\x19.google.protobuf.DurationR\x08\x64uration\x12\x14\n\x05topic\x18\x06 \x01(\tR\x05topic\x12\x18\n\x07request\x18\x07 \x01(\tR\x07request\x12\x19\n\x05\x65rror\x18\x08 \x01(\tH\x01R\x05\x65rror\x88\x01\x01\x42\x0e\n\x0c_request_keyB\x08\n\x06_error\"\xa0\x03\n\x12PubSubConsumeEvent\x12%\n\x0e\x64\x65ployment_key\x18\x01 \x01(\tR\rdeploymentKey\x12$\n\x0brequest_key\x18\x02 \x01(\tH\x00R\nrequestKey\x88\x01\x01\x12-\n\x10\x64\x65st_verb_module\x18\x03 \x01(\tH\x01R\x0e\x64\x65stVerbModule\x88\x01\x01\x12)\n\x0e\x64\x65st_verb_name\x18\x04 \x01(\tH\x02R\x0c\x64\x65stVerbName\x88\x01\x01\x12\x39\n\ntime_stamp\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.TimestampR\ttimeStamp\x12\x35\n\x08\x64uration\x18\x06 \x01(\x0b\x32\x19.google.protobuf.DurationR\x08\x64uration\x12\x14\n\x05topic\x18\x07 \x01(\tR\x05topic\x12\x19\n\x05\x65rror\x18\x08 \x01(\tH\x03R\x05\x65rror\x88\x01\x01\x42\x0e\n\x0c_request_keyB\x13\n\x11_dest_verb_moduleB\x11\n\x0f_dest_verb_nameB\x08\n\x06_error\"\xba\x06\n\x05\x45vent\x12\x39\n\ntime_stamp\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.TimestampR\ttimeStamp\x12\x0e\n\x02id\x18\x02 \x01(\x03R\x02id\x12\x37\n\x03log\x18\x03 \x01(\x0b\x32#.xyz.block.ftl.timeline.v1.LogEventH\x00R\x03log\x12:\n\x04\x63\x61ll\x18\x04 \x01(\x0b\x32$.xyz.block.ftl.timeline.v1.CallEventH\x00R\x04\x63\x61ll\x12\x62\n\x12\x64\x65ployment_created\x18\x05 \x01(\x0b\x32\x31.xyz.block.ftl.timeline.v1.DeploymentCreatedEventH\x00R\x11\x64\x65ploymentCreated\x12\x62\n\x12\x64\x65ployment_updated\x18\x06 \x01(\x0b\x32\x31.xyz.block.ftl.timeline.v1.DeploymentUpdatedEventH\x00R\x11\x64\x65ploymentUpdated\x12\x43\n\x07ingress\x18\x07 \x01(\x0b\x32\'.xyz.block.ftl.timeline.v1.IngressEventH\x00R\x07ingress\x12V\n\x0e\x63ron_scheduled\x18\x08 \x01(\x0b\x32-.xyz.block.ftl.timeline.v1.CronScheduledEventH\x00R\rcronScheduled\x12S\n\rasync_execute\x18\t \x01(\x0b\x32,.xyz.block.ftl.timeline.v1.AsyncExecuteEventH\x00R\x0c\x61syncExecute\x12V\n\x0epubsub_publish\x18\n \x01(\x0b\x32-.xyz.block.ftl.timeline.v1.PubSubPublishEventH\x00R\rpubsubPublish\x12V\n\x0epubsub_consume\x18\x0b \x01(\x0b\x32-.xyz.block.ftl.timeline.v1.PubSubConsumeEventH\x00R\rpubsubConsumeB\x07\n\x05\x65ntry*\xa9\x02\n\tEventType\x12\x1a\n\x16\x45VENT_TYPE_UNSPECIFIED\x10\x00\x12\x12\n\x0e\x45VENT_TYPE_LOG\x10\x01\x12\x13\n\x0f\x45VENT_TYPE_CALL\x10\x02\x12!\n\x1d\x45VENT_TYPE_DEPLOYMENT_CREATED\x10\x03\x12!\n\x1d\x45VENT_TYPE_DEPLOYMENT_UPDATED\x10\x04\x12\x16\n\x12\x45VENT_TYPE_INGRESS\x10\x05\x12\x1d\n\x19\x45VENT_TYPE_CRON_SCHEDULED\x10\x06\x12\x1c\n\x18\x45VENT_TYPE_ASYNC_EXECUTE\x10\x07\x12\x1d\n\x19\x45VENT_TYPE_PUBSUB_PUBLISH\x10\x08\x12\x1d\n\x19\x45VENT_TYPE_PUBSUB_CONSUME\x10\t*\x89\x01\n\x15\x41syncExecuteEventType\x12(\n$ASYNC_EXECUTE_EVENT_TYPE_UNSPECIFIED\x10\x00\x12!\n\x1d\x41SYNC_EXECUTE_EVENT_TYPE_CRON\x10\x01\x12#\n\x1f\x41SYNC_EXECUTE_EVENT_TYPE_PUBSUB\x10\x02*\x8c\x01\n\x08LogLevel\x12\x19\n\x15LOG_LEVEL_UNSPECIFIED\x10\x00\x12\x13\n\x0fLOG_LEVEL_TRACE\x10\x01\x12\x13\n\x0fLOG_LEVEL_DEBUG\x10\x05\x12\x12\n\x0eLOG_LEVEL_INFO\x10\t\x12\x12\n\x0eLOG_LEVEL_WARN\x10\r\x12\x13\n\x0fLOG_LEVEL_ERROR\x10\x11\x42RP\x01ZNgithub.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/timeline/v1;timelinev1b\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n%xyz/block/ftl/timeline/v1/event.proto\x12\x19xyz.block.ftl.timeline.v1\x1a\x1egoogle/protobuf/duration.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a$xyz/block/ftl/schema/v1/schema.proto\"\xb6\x03\n\x08LogEvent\x12%\n\x0e\x64\x65ployment_key\x18\x01 \x01(\tR\rdeploymentKey\x12$\n\x0brequest_key\x18\x02 \x01(\tH\x00R\nrequestKey\x88\x01\x01\x12\x38\n\ttimestamp\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.TimestampR\ttimestamp\x12\x1b\n\tlog_level\x18\x04 \x01(\x05R\x08logLevel\x12S\n\nattributes\x18\x05 \x03(\x0b\x32\x33.xyz.block.ftl.timeline.v1.LogEvent.AttributesEntryR\nattributes\x12\x18\n\x07message\x18\x06 \x01(\tR\x07message\x12\x19\n\x05\x65rror\x18\x07 \x01(\tH\x01R\x05\x65rror\x88\x01\x01\x12\x19\n\x05stack\x18\x08 \x01(\tH\x02R\x05stack\x88\x01\x01\x1a=\n\x0f\x41ttributesEntry\x12\x10\n\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n\x05value\x18\x02 \x01(\tR\x05value:\x02\x38\x01\x42\x0e\n\x0c_request_keyB\x08\n\x06_errorB\x08\n\x06_stack\"\x94\x04\n\tCallEvent\x12$\n\x0brequest_key\x18\x01 \x01(\tH\x00R\nrequestKey\x88\x01\x01\x12%\n\x0e\x64\x65ployment_key\x18\x02 \x01(\tR\rdeploymentKey\x12\x38\n\ttimestamp\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.TimestampR\ttimestamp\x12I\n\x0fsource_verb_ref\x18\x0b \x01(\x0b\x32\x1c.xyz.block.ftl.schema.v1.RefH\x01R\rsourceVerbRef\x88\x01\x01\x12N\n\x14\x64\x65stination_verb_ref\x18\x0c \x01(\x0b\x32\x1c.xyz.block.ftl.schema.v1.RefR\x12\x64\x65stinationVerbRef\x12\x35\n\x08\x64uration\x18\x06 \x01(\x0b\x32\x19.google.protobuf.DurationR\x08\x64uration\x12\x18\n\x07request\x18\x07 \x01(\tR\x07request\x12\x1a\n\x08response\x18\x08 \x01(\tR\x08response\x12\x19\n\x05\x65rror\x18\t \x01(\tH\x02R\x05\x65rror\x88\x01\x01\x12\x19\n\x05stack\x18\n \x01(\tH\x03R\x05stack\x88\x01\x01\x42\x0e\n\x0c_request_keyB\x12\n\x10_source_verb_refB\x08\n\x06_errorB\x08\n\x06_stackJ\x04\x08\x04\x10\x05J\x04\x08\x05\x10\x06\"\xb8\x01\n\x16\x44\x65ploymentCreatedEvent\x12\x10\n\x03key\x18\x01 \x01(\tR\x03key\x12\x1a\n\x08language\x18\x02 \x01(\tR\x08language\x12\x1f\n\x0bmodule_name\x18\x03 \x01(\tR\nmoduleName\x12!\n\x0cmin_replicas\x18\x04 \x01(\x05R\x0bminReplicas\x12\x1f\n\x08replaced\x18\x05 \x01(\tH\x00R\x08replaced\x88\x01\x01\x42\x0b\n\t_replaced\"y\n\x16\x44\x65ploymentUpdatedEvent\x12\x10\n\x03key\x18\x01 \x01(\tR\x03key\x12!\n\x0cmin_replicas\x18\x02 \x01(\x05R\x0bminReplicas\x12*\n\x11prev_min_replicas\x18\x03 \x01(\x05R\x0fprevMinReplicas\"\x8d\x04\n\x0cIngressEvent\x12%\n\x0e\x64\x65ployment_key\x18\x01 \x01(\tR\rdeploymentKey\x12$\n\x0brequest_key\x18\x02 \x01(\tH\x00R\nrequestKey\x88\x01\x01\x12\x37\n\x08verb_ref\x18\x03 \x01(\x0b\x32\x1c.xyz.block.ftl.schema.v1.RefR\x07verbRef\x12\x16\n\x06method\x18\x04 \x01(\tR\x06method\x12\x12\n\x04path\x18\x05 \x01(\tR\x04path\x12\x1f\n\x0bstatus_code\x18\x07 \x01(\x05R\nstatusCode\x12\x38\n\ttimestamp\x18\x08 \x01(\x0b\x32\x1a.google.protobuf.TimestampR\ttimestamp\x12\x35\n\x08\x64uration\x18\t \x01(\x0b\x32\x19.google.protobuf.DurationR\x08\x64uration\x12\x18\n\x07request\x18\n \x01(\tR\x07request\x12%\n\x0erequest_header\x18\x0b \x01(\tR\rrequestHeader\x12\x1a\n\x08response\x18\x0c \x01(\tR\x08response\x12\'\n\x0fresponse_header\x18\r \x01(\tR\x0eresponseHeader\x12\x19\n\x05\x65rror\x18\x0e \x01(\tH\x01R\x05\x65rror\x88\x01\x01\x42\x0e\n\x0c_request_keyB\x08\n\x06_error\"\xe5\x02\n\x12\x43ronScheduledEvent\x12%\n\x0e\x64\x65ployment_key\x18\x01 \x01(\tR\rdeploymentKey\x12\x37\n\x08verb_ref\x18\x02 \x01(\x0b\x32\x1c.xyz.block.ftl.schema.v1.RefR\x07verbRef\x12\x38\n\ttimestamp\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.TimestampR\ttimestamp\x12\x35\n\x08\x64uration\x18\x04 \x01(\x0b\x32\x19.google.protobuf.DurationR\x08\x64uration\x12=\n\x0cscheduled_at\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.TimestampR\x0bscheduledAt\x12\x1a\n\x08schedule\x18\x06 \x01(\tR\x08schedule\x12\x19\n\x05\x65rror\x18\x07 \x01(\tH\x00R\x05\x65rror\x88\x01\x01\x42\x08\n\x06_error\"\x9b\x03\n\x11\x41syncExecuteEvent\x12%\n\x0e\x64\x65ployment_key\x18\x01 \x01(\tR\rdeploymentKey\x12$\n\x0brequest_key\x18\x02 \x01(\tH\x00R\nrequestKey\x88\x01\x01\x12\x37\n\x08verb_ref\x18\x03 \x01(\x0b\x32\x1c.xyz.block.ftl.schema.v1.RefR\x07verbRef\x12\x38\n\ttimestamp\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.TimestampR\ttimestamp\x12\x35\n\x08\x64uration\x18\x05 \x01(\x0b\x32\x19.google.protobuf.DurationR\x08\x64uration\x12Z\n\x10\x61sync_event_type\x18\x06 \x01(\x0e\x32\x30.xyz.block.ftl.timeline.v1.AsyncExecuteEventTypeR\x0e\x61syncEventType\x12\x19\n\x05\x65rror\x18\x07 \x01(\tH\x01R\x05\x65rror\x88\x01\x01\x42\x0e\n\x0c_request_keyB\x08\n\x06_error\"\xf0\x02\n\x12PubSubPublishEvent\x12%\n\x0e\x64\x65ployment_key\x18\x01 \x01(\tR\rdeploymentKey\x12$\n\x0brequest_key\x18\x02 \x01(\tH\x00R\nrequestKey\x88\x01\x01\x12\x37\n\x08verb_ref\x18\x03 \x01(\x0b\x32\x1c.xyz.block.ftl.schema.v1.RefR\x07verbRef\x12\x38\n\ttimestamp\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.TimestampR\ttimestamp\x12\x35\n\x08\x64uration\x18\x05 \x01(\x0b\x32\x19.google.protobuf.DurationR\x08\x64uration\x12\x14\n\x05topic\x18\x06 \x01(\tR\x05topic\x12\x18\n\x07request\x18\x07 \x01(\tR\x07request\x12\x19\n\x05\x65rror\x18\x08 \x01(\tH\x01R\x05\x65rror\x88\x01\x01\x42\x0e\n\x0c_request_keyB\x08\n\x06_error\"\x9f\x03\n\x12PubSubConsumeEvent\x12%\n\x0e\x64\x65ployment_key\x18\x01 \x01(\tR\rdeploymentKey\x12$\n\x0brequest_key\x18\x02 \x01(\tH\x00R\nrequestKey\x88\x01\x01\x12-\n\x10\x64\x65st_verb_module\x18\x03 \x01(\tH\x01R\x0e\x64\x65stVerbModule\x88\x01\x01\x12)\n\x0e\x64\x65st_verb_name\x18\x04 \x01(\tH\x02R\x0c\x64\x65stVerbName\x88\x01\x01\x12\x38\n\ttimestamp\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.TimestampR\ttimestamp\x12\x35\n\x08\x64uration\x18\x06 \x01(\x0b\x32\x19.google.protobuf.DurationR\x08\x64uration\x12\x14\n\x05topic\x18\x07 \x01(\tR\x05topic\x12\x19\n\x05\x65rror\x18\x08 \x01(\tH\x03R\x05\x65rror\x88\x01\x01\x42\x0e\n\x0c_request_keyB\x13\n\x11_dest_verb_moduleB\x11\n\x0f_dest_verb_nameB\x08\n\x06_error\"\xb9\x06\n\x05\x45vent\x12\x38\n\ttimestamp\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.TimestampR\ttimestamp\x12\x0e\n\x02id\x18\x02 \x01(\x03R\x02id\x12\x37\n\x03log\x18\x03 \x01(\x0b\x32#.xyz.block.ftl.timeline.v1.LogEventH\x00R\x03log\x12:\n\x04\x63\x61ll\x18\x04 \x01(\x0b\x32$.xyz.block.ftl.timeline.v1.CallEventH\x00R\x04\x63\x61ll\x12\x62\n\x12\x64\x65ployment_created\x18\x05 \x01(\x0b\x32\x31.xyz.block.ftl.timeline.v1.DeploymentCreatedEventH\x00R\x11\x64\x65ploymentCreated\x12\x62\n\x12\x64\x65ployment_updated\x18\x06 \x01(\x0b\x32\x31.xyz.block.ftl.timeline.v1.DeploymentUpdatedEventH\x00R\x11\x64\x65ploymentUpdated\x12\x43\n\x07ingress\x18\x07 \x01(\x0b\x32\'.xyz.block.ftl.timeline.v1.IngressEventH\x00R\x07ingress\x12V\n\x0e\x63ron_scheduled\x18\x08 \x01(\x0b\x32-.xyz.block.ftl.timeline.v1.CronScheduledEventH\x00R\rcronScheduled\x12S\n\rasync_execute\x18\t \x01(\x0b\x32,.xyz.block.ftl.timeline.v1.AsyncExecuteEventH\x00R\x0c\x61syncExecute\x12V\n\x0epubsub_publish\x18\n \x01(\x0b\x32-.xyz.block.ftl.timeline.v1.PubSubPublishEventH\x00R\rpubsubPublish\x12V\n\x0epubsub_consume\x18\x0b \x01(\x0b\x32-.xyz.block.ftl.timeline.v1.PubSubConsumeEventH\x00R\rpubsubConsumeB\x07\n\x05\x65ntry*\xa9\x02\n\tEventType\x12\x1a\n\x16\x45VENT_TYPE_UNSPECIFIED\x10\x00\x12\x12\n\x0e\x45VENT_TYPE_LOG\x10\x01\x12\x13\n\x0f\x45VENT_TYPE_CALL\x10\x02\x12!\n\x1d\x45VENT_TYPE_DEPLOYMENT_CREATED\x10\x03\x12!\n\x1d\x45VENT_TYPE_DEPLOYMENT_UPDATED\x10\x04\x12\x16\n\x12\x45VENT_TYPE_INGRESS\x10\x05\x12\x1d\n\x19\x45VENT_TYPE_CRON_SCHEDULED\x10\x06\x12\x1c\n\x18\x45VENT_TYPE_ASYNC_EXECUTE\x10\x07\x12\x1d\n\x19\x45VENT_TYPE_PUBSUB_PUBLISH\x10\x08\x12\x1d\n\x19\x45VENT_TYPE_PUBSUB_CONSUME\x10\t*\x89\x01\n\x15\x41syncExecuteEventType\x12(\n$ASYNC_EXECUTE_EVENT_TYPE_UNSPECIFIED\x10\x00\x12!\n\x1d\x41SYNC_EXECUTE_EVENT_TYPE_CRON\x10\x01\x12#\n\x1f\x41SYNC_EXECUTE_EVENT_TYPE_PUBSUB\x10\x02*\x8c\x01\n\x08LogLevel\x12\x19\n\x15LOG_LEVEL_UNSPECIFIED\x10\x00\x12\x13\n\x0fLOG_LEVEL_TRACE\x10\x01\x12\x13\n\x0fLOG_LEVEL_DEBUG\x10\x05\x12\x12\n\x0eLOG_LEVEL_INFO\x10\t\x12\x12\n\x0eLOG_LEVEL_WARN\x10\r\x12\x13\n\x0fLOG_LEVEL_ERROR\x10\x11\x42RP\x01ZNgithub.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/timeline/v1;timelinev1b\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) @@ -37,32 +37,32 @@ _globals['DESCRIPTOR']._serialized_options = b'P\001ZNgithub.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/timeline/v1;timelinev1' _globals['_LOGEVENT_ATTRIBUTESENTRY']._loaded_options = None _globals['_LOGEVENT_ATTRIBUTESENTRY']._serialized_options = b'8\001' - _globals['_EVENTTYPE']._serialized_start=4385 - _globals['_EVENTTYPE']._serialized_end=4682 - _globals['_ASYNCEXECUTEEVENTTYPE']._serialized_start=4685 - _globals['_ASYNCEXECUTEEVENTTYPE']._serialized_end=4822 - _globals['_LOGLEVEL']._serialized_start=4825 - _globals['_LOGLEVEL']._serialized_end=4965 + _globals['_EVENTTYPE']._serialized_start=4377 + _globals['_EVENTTYPE']._serialized_end=4674 + _globals['_ASYNCEXECUTEEVENTTYPE']._serialized_start=4677 + _globals['_ASYNCEXECUTEEVENTTYPE']._serialized_end=4814 + _globals['_LOGLEVEL']._serialized_start=4817 + _globals['_LOGLEVEL']._serialized_end=4957 _globals['_LOGEVENT']._serialized_start=172 - _globals['_LOGEVENT']._serialized_end=611 - _globals['_LOGEVENT_ATTRIBUTESENTRY']._serialized_start=514 - _globals['_LOGEVENT_ATTRIBUTESENTRY']._serialized_end=575 - _globals['_CALLEVENT']._serialized_start=614 - _globals['_CALLEVENT']._serialized_end=1147 - _globals['_DEPLOYMENTCREATEDEVENT']._serialized_start=1150 - _globals['_DEPLOYMENTCREATEDEVENT']._serialized_end=1334 - _globals['_DEPLOYMENTUPDATEDEVENT']._serialized_start=1336 - _globals['_DEPLOYMENTUPDATEDEVENT']._serialized_end=1457 - _globals['_INGRESSEVENT']._serialized_start=1460 - _globals['_INGRESSEVENT']._serialized_end=1986 - _globals['_CRONSCHEDULEDEVENT']._serialized_start=1989 - _globals['_CRONSCHEDULEDEVENT']._serialized_end=2347 - _globals['_ASYNCEXECUTEEVENT']._serialized_start=2350 - _globals['_ASYNCEXECUTEEVENT']._serialized_end=2762 - _globals['_PUBSUBPUBLISHEVENT']._serialized_start=2765 - _globals['_PUBSUBPUBLISHEVENT']._serialized_end=3134 - _globals['_PUBSUBCONSUMEEVENT']._serialized_start=3137 - _globals['_PUBSUBCONSUMEEVENT']._serialized_end=3553 - _globals['_EVENT']._serialized_start=3556 - _globals['_EVENT']._serialized_end=4382 + _globals['_LOGEVENT']._serialized_end=610 + _globals['_LOGEVENT_ATTRIBUTESENTRY']._serialized_start=513 + _globals['_LOGEVENT_ATTRIBUTESENTRY']._serialized_end=574 + _globals['_CALLEVENT']._serialized_start=613 + _globals['_CALLEVENT']._serialized_end=1145 + _globals['_DEPLOYMENTCREATEDEVENT']._serialized_start=1148 + _globals['_DEPLOYMENTCREATEDEVENT']._serialized_end=1332 + _globals['_DEPLOYMENTUPDATEDEVENT']._serialized_start=1334 + _globals['_DEPLOYMENTUPDATEDEVENT']._serialized_end=1455 + _globals['_INGRESSEVENT']._serialized_start=1458 + _globals['_INGRESSEVENT']._serialized_end=1983 + _globals['_CRONSCHEDULEDEVENT']._serialized_start=1986 + _globals['_CRONSCHEDULEDEVENT']._serialized_end=2343 + _globals['_ASYNCEXECUTEEVENT']._serialized_start=2346 + _globals['_ASYNCEXECUTEEVENT']._serialized_end=2757 + _globals['_PUBSUBPUBLISHEVENT']._serialized_start=2760 + _globals['_PUBSUBPUBLISHEVENT']._serialized_end=3128 + _globals['_PUBSUBCONSUMEEVENT']._serialized_start=3131 + _globals['_PUBSUBCONSUMEEVENT']._serialized_end=3546 + _globals['_EVENT']._serialized_start=3549 + _globals['_EVENT']._serialized_end=4374 # @@protoc_insertion_point(module_scope) diff --git a/python-runtime/ftl/src/ftl/protos/xyz/block/ftl/timeline/v1/event_pb2.pyi b/python-runtime/ftl/src/ftl/protos/xyz/block/ftl/timeline/v1/event_pb2.pyi index b87ae577f4..12d60460bc 100644 --- a/python-runtime/ftl/src/ftl/protos/xyz/block/ftl/timeline/v1/event_pb2.pyi +++ b/python-runtime/ftl/src/ftl/protos/xyz/block/ftl/timeline/v1/event_pb2.pyi @@ -57,7 +57,7 @@ LOG_LEVEL_WARN: LogLevel LOG_LEVEL_ERROR: LogLevel class LogEvent(_message.Message): - __slots__ = ("deployment_key", "request_key", "time_stamp", "log_level", "attributes", "message", "error", "stack") + __slots__ = ("deployment_key", "request_key", "timestamp", "log_level", "attributes", "message", "error", "stack") class AttributesEntry(_message.Message): __slots__ = ("key", "value") KEY_FIELD_NUMBER: _ClassVar[int] @@ -67,7 +67,7 @@ class LogEvent(_message.Message): def __init__(self, key: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ... DEPLOYMENT_KEY_FIELD_NUMBER: _ClassVar[int] REQUEST_KEY_FIELD_NUMBER: _ClassVar[int] - TIME_STAMP_FIELD_NUMBER: _ClassVar[int] + TIMESTAMP_FIELD_NUMBER: _ClassVar[int] LOG_LEVEL_FIELD_NUMBER: _ClassVar[int] ATTRIBUTES_FIELD_NUMBER: _ClassVar[int] MESSAGE_FIELD_NUMBER: _ClassVar[int] @@ -75,19 +75,19 @@ class LogEvent(_message.Message): STACK_FIELD_NUMBER: _ClassVar[int] deployment_key: str request_key: str - time_stamp: _timestamp_pb2.Timestamp + timestamp: _timestamp_pb2.Timestamp log_level: int attributes: _containers.ScalarMap[str, str] message: str error: str stack: str - def __init__(self, deployment_key: _Optional[str] = ..., request_key: _Optional[str] = ..., time_stamp: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., log_level: _Optional[int] = ..., attributes: _Optional[_Mapping[str, str]] = ..., message: _Optional[str] = ..., error: _Optional[str] = ..., stack: _Optional[str] = ...) -> None: ... + def __init__(self, deployment_key: _Optional[str] = ..., request_key: _Optional[str] = ..., timestamp: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., log_level: _Optional[int] = ..., attributes: _Optional[_Mapping[str, str]] = ..., message: _Optional[str] = ..., error: _Optional[str] = ..., stack: _Optional[str] = ...) -> None: ... class CallEvent(_message.Message): - __slots__ = ("request_key", "deployment_key", "time_stamp", "source_verb_ref", "destination_verb_ref", "duration", "request", "response", "error", "stack") + __slots__ = ("request_key", "deployment_key", "timestamp", "source_verb_ref", "destination_verb_ref", "duration", "request", "response", "error", "stack") REQUEST_KEY_FIELD_NUMBER: _ClassVar[int] DEPLOYMENT_KEY_FIELD_NUMBER: _ClassVar[int] - TIME_STAMP_FIELD_NUMBER: _ClassVar[int] + TIMESTAMP_FIELD_NUMBER: _ClassVar[int] SOURCE_VERB_REF_FIELD_NUMBER: _ClassVar[int] DESTINATION_VERB_REF_FIELD_NUMBER: _ClassVar[int] DURATION_FIELD_NUMBER: _ClassVar[int] @@ -97,7 +97,7 @@ class CallEvent(_message.Message): STACK_FIELD_NUMBER: _ClassVar[int] request_key: str deployment_key: str - time_stamp: _timestamp_pb2.Timestamp + timestamp: _timestamp_pb2.Timestamp source_verb_ref: _schema_pb2.Ref destination_verb_ref: _schema_pb2.Ref duration: _duration_pb2.Duration @@ -105,7 +105,7 @@ class CallEvent(_message.Message): response: str error: str stack: str - def __init__(self, request_key: _Optional[str] = ..., deployment_key: _Optional[str] = ..., time_stamp: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., source_verb_ref: _Optional[_Union[_schema_pb2.Ref, _Mapping]] = ..., destination_verb_ref: _Optional[_Union[_schema_pb2.Ref, _Mapping]] = ..., duration: _Optional[_Union[_duration_pb2.Duration, _Mapping]] = ..., request: _Optional[str] = ..., response: _Optional[str] = ..., error: _Optional[str] = ..., stack: _Optional[str] = ...) -> None: ... + def __init__(self, request_key: _Optional[str] = ..., deployment_key: _Optional[str] = ..., timestamp: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., source_verb_ref: _Optional[_Union[_schema_pb2.Ref, _Mapping]] = ..., destination_verb_ref: _Optional[_Union[_schema_pb2.Ref, _Mapping]] = ..., duration: _Optional[_Union[_duration_pb2.Duration, _Mapping]] = ..., request: _Optional[str] = ..., response: _Optional[str] = ..., error: _Optional[str] = ..., stack: _Optional[str] = ...) -> None: ... class DeploymentCreatedEvent(_message.Message): __slots__ = ("key", "language", "module_name", "min_replicas", "replaced") @@ -132,14 +132,14 @@ class DeploymentUpdatedEvent(_message.Message): def __init__(self, key: _Optional[str] = ..., min_replicas: _Optional[int] = ..., prev_min_replicas: _Optional[int] = ...) -> None: ... class IngressEvent(_message.Message): - __slots__ = ("deployment_key", "request_key", "verb_ref", "method", "path", "status_code", "time_stamp", "duration", "request", "request_header", "response", "response_header", "error") + __slots__ = ("deployment_key", "request_key", "verb_ref", "method", "path", "status_code", "timestamp", "duration", "request", "request_header", "response", "response_header", "error") DEPLOYMENT_KEY_FIELD_NUMBER: _ClassVar[int] REQUEST_KEY_FIELD_NUMBER: _ClassVar[int] VERB_REF_FIELD_NUMBER: _ClassVar[int] METHOD_FIELD_NUMBER: _ClassVar[int] PATH_FIELD_NUMBER: _ClassVar[int] STATUS_CODE_FIELD_NUMBER: _ClassVar[int] - TIME_STAMP_FIELD_NUMBER: _ClassVar[int] + TIMESTAMP_FIELD_NUMBER: _ClassVar[int] DURATION_FIELD_NUMBER: _ClassVar[int] REQUEST_FIELD_NUMBER: _ClassVar[int] REQUEST_HEADER_FIELD_NUMBER: _ClassVar[int] @@ -152,57 +152,57 @@ class IngressEvent(_message.Message): method: str path: str status_code: int - time_stamp: _timestamp_pb2.Timestamp + timestamp: _timestamp_pb2.Timestamp duration: _duration_pb2.Duration request: str request_header: str response: str response_header: str error: str - def __init__(self, deployment_key: _Optional[str] = ..., request_key: _Optional[str] = ..., verb_ref: _Optional[_Union[_schema_pb2.Ref, _Mapping]] = ..., method: _Optional[str] = ..., path: _Optional[str] = ..., status_code: _Optional[int] = ..., time_stamp: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., duration: _Optional[_Union[_duration_pb2.Duration, _Mapping]] = ..., request: _Optional[str] = ..., request_header: _Optional[str] = ..., response: _Optional[str] = ..., response_header: _Optional[str] = ..., error: _Optional[str] = ...) -> None: ... + def __init__(self, deployment_key: _Optional[str] = ..., request_key: _Optional[str] = ..., verb_ref: _Optional[_Union[_schema_pb2.Ref, _Mapping]] = ..., method: _Optional[str] = ..., path: _Optional[str] = ..., status_code: _Optional[int] = ..., timestamp: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., duration: _Optional[_Union[_duration_pb2.Duration, _Mapping]] = ..., request: _Optional[str] = ..., request_header: _Optional[str] = ..., response: _Optional[str] = ..., response_header: _Optional[str] = ..., error: _Optional[str] = ...) -> None: ... class CronScheduledEvent(_message.Message): - __slots__ = ("deployment_key", "verb_ref", "time_stamp", "duration", "scheduled_at", "schedule", "error") + __slots__ = ("deployment_key", "verb_ref", "timestamp", "duration", "scheduled_at", "schedule", "error") DEPLOYMENT_KEY_FIELD_NUMBER: _ClassVar[int] VERB_REF_FIELD_NUMBER: _ClassVar[int] - TIME_STAMP_FIELD_NUMBER: _ClassVar[int] + TIMESTAMP_FIELD_NUMBER: _ClassVar[int] DURATION_FIELD_NUMBER: _ClassVar[int] SCHEDULED_AT_FIELD_NUMBER: _ClassVar[int] SCHEDULE_FIELD_NUMBER: _ClassVar[int] ERROR_FIELD_NUMBER: _ClassVar[int] deployment_key: str verb_ref: _schema_pb2.Ref - time_stamp: _timestamp_pb2.Timestamp + timestamp: _timestamp_pb2.Timestamp duration: _duration_pb2.Duration scheduled_at: _timestamp_pb2.Timestamp schedule: str error: str - def __init__(self, deployment_key: _Optional[str] = ..., verb_ref: _Optional[_Union[_schema_pb2.Ref, _Mapping]] = ..., time_stamp: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., duration: _Optional[_Union[_duration_pb2.Duration, _Mapping]] = ..., scheduled_at: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., schedule: _Optional[str] = ..., error: _Optional[str] = ...) -> None: ... + def __init__(self, deployment_key: _Optional[str] = ..., verb_ref: _Optional[_Union[_schema_pb2.Ref, _Mapping]] = ..., timestamp: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., duration: _Optional[_Union[_duration_pb2.Duration, _Mapping]] = ..., scheduled_at: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., schedule: _Optional[str] = ..., error: _Optional[str] = ...) -> None: ... class AsyncExecuteEvent(_message.Message): - __slots__ = ("deployment_key", "request_key", "verb_ref", "time_stamp", "duration", "async_event_type", "error") + __slots__ = ("deployment_key", "request_key", "verb_ref", "timestamp", "duration", "async_event_type", "error") DEPLOYMENT_KEY_FIELD_NUMBER: _ClassVar[int] REQUEST_KEY_FIELD_NUMBER: _ClassVar[int] VERB_REF_FIELD_NUMBER: _ClassVar[int] - TIME_STAMP_FIELD_NUMBER: _ClassVar[int] + TIMESTAMP_FIELD_NUMBER: _ClassVar[int] DURATION_FIELD_NUMBER: _ClassVar[int] ASYNC_EVENT_TYPE_FIELD_NUMBER: _ClassVar[int] ERROR_FIELD_NUMBER: _ClassVar[int] deployment_key: str request_key: str verb_ref: _schema_pb2.Ref - time_stamp: _timestamp_pb2.Timestamp + timestamp: _timestamp_pb2.Timestamp duration: _duration_pb2.Duration async_event_type: AsyncExecuteEventType error: str - def __init__(self, deployment_key: _Optional[str] = ..., request_key: _Optional[str] = ..., verb_ref: _Optional[_Union[_schema_pb2.Ref, _Mapping]] = ..., time_stamp: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., duration: _Optional[_Union[_duration_pb2.Duration, _Mapping]] = ..., async_event_type: _Optional[_Union[AsyncExecuteEventType, str]] = ..., error: _Optional[str] = ...) -> None: ... + def __init__(self, deployment_key: _Optional[str] = ..., request_key: _Optional[str] = ..., verb_ref: _Optional[_Union[_schema_pb2.Ref, _Mapping]] = ..., timestamp: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., duration: _Optional[_Union[_duration_pb2.Duration, _Mapping]] = ..., async_event_type: _Optional[_Union[AsyncExecuteEventType, str]] = ..., error: _Optional[str] = ...) -> None: ... class PubSubPublishEvent(_message.Message): - __slots__ = ("deployment_key", "request_key", "verb_ref", "time_stamp", "duration", "topic", "request", "error") + __slots__ = ("deployment_key", "request_key", "verb_ref", "timestamp", "duration", "topic", "request", "error") DEPLOYMENT_KEY_FIELD_NUMBER: _ClassVar[int] REQUEST_KEY_FIELD_NUMBER: _ClassVar[int] VERB_REF_FIELD_NUMBER: _ClassVar[int] - TIME_STAMP_FIELD_NUMBER: _ClassVar[int] + TIMESTAMP_FIELD_NUMBER: _ClassVar[int] DURATION_FIELD_NUMBER: _ClassVar[int] TOPIC_FIELD_NUMBER: _ClassVar[int] REQUEST_FIELD_NUMBER: _ClassVar[int] @@ -210,20 +210,20 @@ class PubSubPublishEvent(_message.Message): deployment_key: str request_key: str verb_ref: _schema_pb2.Ref - time_stamp: _timestamp_pb2.Timestamp + timestamp: _timestamp_pb2.Timestamp duration: _duration_pb2.Duration topic: str request: str error: str - def __init__(self, deployment_key: _Optional[str] = ..., request_key: _Optional[str] = ..., verb_ref: _Optional[_Union[_schema_pb2.Ref, _Mapping]] = ..., time_stamp: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., duration: _Optional[_Union[_duration_pb2.Duration, _Mapping]] = ..., topic: _Optional[str] = ..., request: _Optional[str] = ..., error: _Optional[str] = ...) -> None: ... + def __init__(self, deployment_key: _Optional[str] = ..., request_key: _Optional[str] = ..., verb_ref: _Optional[_Union[_schema_pb2.Ref, _Mapping]] = ..., timestamp: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., duration: _Optional[_Union[_duration_pb2.Duration, _Mapping]] = ..., topic: _Optional[str] = ..., request: _Optional[str] = ..., error: _Optional[str] = ...) -> None: ... class PubSubConsumeEvent(_message.Message): - __slots__ = ("deployment_key", "request_key", "dest_verb_module", "dest_verb_name", "time_stamp", "duration", "topic", "error") + __slots__ = ("deployment_key", "request_key", "dest_verb_module", "dest_verb_name", "timestamp", "duration", "topic", "error") DEPLOYMENT_KEY_FIELD_NUMBER: _ClassVar[int] REQUEST_KEY_FIELD_NUMBER: _ClassVar[int] DEST_VERB_MODULE_FIELD_NUMBER: _ClassVar[int] DEST_VERB_NAME_FIELD_NUMBER: _ClassVar[int] - TIME_STAMP_FIELD_NUMBER: _ClassVar[int] + TIMESTAMP_FIELD_NUMBER: _ClassVar[int] DURATION_FIELD_NUMBER: _ClassVar[int] TOPIC_FIELD_NUMBER: _ClassVar[int] ERROR_FIELD_NUMBER: _ClassVar[int] @@ -231,15 +231,15 @@ class PubSubConsumeEvent(_message.Message): request_key: str dest_verb_module: str dest_verb_name: str - time_stamp: _timestamp_pb2.Timestamp + timestamp: _timestamp_pb2.Timestamp duration: _duration_pb2.Duration topic: str error: str - def __init__(self, deployment_key: _Optional[str] = ..., request_key: _Optional[str] = ..., dest_verb_module: _Optional[str] = ..., dest_verb_name: _Optional[str] = ..., time_stamp: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., duration: _Optional[_Union[_duration_pb2.Duration, _Mapping]] = ..., topic: _Optional[str] = ..., error: _Optional[str] = ...) -> None: ... + def __init__(self, deployment_key: _Optional[str] = ..., request_key: _Optional[str] = ..., dest_verb_module: _Optional[str] = ..., dest_verb_name: _Optional[str] = ..., timestamp: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., duration: _Optional[_Union[_duration_pb2.Duration, _Mapping]] = ..., topic: _Optional[str] = ..., error: _Optional[str] = ...) -> None: ... class Event(_message.Message): - __slots__ = ("time_stamp", "id", "log", "call", "deployment_created", "deployment_updated", "ingress", "cron_scheduled", "async_execute", "pubsub_publish", "pubsub_consume") - TIME_STAMP_FIELD_NUMBER: _ClassVar[int] + __slots__ = ("timestamp", "id", "log", "call", "deployment_created", "deployment_updated", "ingress", "cron_scheduled", "async_execute", "pubsub_publish", "pubsub_consume") + TIMESTAMP_FIELD_NUMBER: _ClassVar[int] ID_FIELD_NUMBER: _ClassVar[int] LOG_FIELD_NUMBER: _ClassVar[int] CALL_FIELD_NUMBER: _ClassVar[int] @@ -250,7 +250,7 @@ class Event(_message.Message): ASYNC_EXECUTE_FIELD_NUMBER: _ClassVar[int] PUBSUB_PUBLISH_FIELD_NUMBER: _ClassVar[int] PUBSUB_CONSUME_FIELD_NUMBER: _ClassVar[int] - time_stamp: _timestamp_pb2.Timestamp + timestamp: _timestamp_pb2.Timestamp id: int log: LogEvent call: CallEvent @@ -261,4 +261,4 @@ class Event(_message.Message): async_execute: AsyncExecuteEvent pubsub_publish: PubSubPublishEvent pubsub_consume: PubSubConsumeEvent - def __init__(self, time_stamp: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., id: _Optional[int] = ..., log: _Optional[_Union[LogEvent, _Mapping]] = ..., call: _Optional[_Union[CallEvent, _Mapping]] = ..., deployment_created: _Optional[_Union[DeploymentCreatedEvent, _Mapping]] = ..., deployment_updated: _Optional[_Union[DeploymentUpdatedEvent, _Mapping]] = ..., ingress: _Optional[_Union[IngressEvent, _Mapping]] = ..., cron_scheduled: _Optional[_Union[CronScheduledEvent, _Mapping]] = ..., async_execute: _Optional[_Union[AsyncExecuteEvent, _Mapping]] = ..., pubsub_publish: _Optional[_Union[PubSubPublishEvent, _Mapping]] = ..., pubsub_consume: _Optional[_Union[PubSubConsumeEvent, _Mapping]] = ...) -> None: ... + def __init__(self, timestamp: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., id: _Optional[int] = ..., log: _Optional[_Union[LogEvent, _Mapping]] = ..., call: _Optional[_Union[CallEvent, _Mapping]] = ..., deployment_created: _Optional[_Union[DeploymentCreatedEvent, _Mapping]] = ..., deployment_updated: _Optional[_Union[DeploymentUpdatedEvent, _Mapping]] = ..., ingress: _Optional[_Union[IngressEvent, _Mapping]] = ..., cron_scheduled: _Optional[_Union[CronScheduledEvent, _Mapping]] = ..., async_execute: _Optional[_Union[AsyncExecuteEvent, _Mapping]] = ..., pubsub_publish: _Optional[_Union[PubSubPublishEvent, _Mapping]] = ..., pubsub_consume: _Optional[_Union[PubSubConsumeEvent, _Mapping]] = ...) -> None: ... diff --git a/sqlc.yaml b/sqlc.yaml index 609a22d7fe..60f45a30fc 100644 --- a/sqlc.yaml +++ b/sqlc.yaml @@ -6,8 +6,6 @@ sql: - backend/controller/dal/internal/sql/queries.sql - backend/controller/dal/internal/sql/async_queries.sql - backend/controller/pubsub/internal/sql/queries.sql - # Some of the timeline entries happen within a controller transaction, so we need to include them here - - backend/controller/timeline/internal/sql/deployment_queries.sql schema: "backend/controller/sql/schema" database: uri: postgres://localhost:15432/ftl?sslmode=disable&user=postgres&password=secret @@ -166,14 +164,6 @@ sql: go: <<: *gengo out: "backend/controller/encryption/internal/sql" - - <<: *daldir - queries: - - backend/controller/timeline/internal/sql/queries.sql - - backend/controller/timeline/internal/sql/deployment_queries.sql - gen: - go: - <<: *gengo - out: "backend/controller/timeline/internal/sql" - <<: *daldir queries: - backend/controller/pubsub/internal/sql/queries.sql