-
-
Notifications
You must be signed in to change notification settings - Fork 4.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(aci): Add new GroupOpenPeriod table #87813
Conversation
This PR has a migration; here is the generated SQL for --
-- Create model GroupOpenPeriod
--
CREATE TABLE "sentry_groupopenperiod" ("id" bigint NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY, "user_id" bigint NULL, "date_started" timestamp with time zone NOT NULL, "date_ended" timestamp with time zone NULL, "data" text NULL, "data_condition_id" bigint NULL, "group_id" bigint NOT NULL, "project_id" bigint NOT NULL, "resolution_activity_id" bigint NULL);
ALTER TABLE "sentry_groupopenperiod" ADD CONSTRAINT "sentry_groupopenperi_data_condition_id_ac18ad82_fk_workflow_" FOREIGN KEY ("data_condition_id") REFERENCES "workflow_engine_datacondition" ("id") DEFERRABLE INITIALLY DEFERRED NOT VALID;
ALTER TABLE "sentry_groupopenperiod" VALIDATE CONSTRAINT "sentry_groupopenperi_data_condition_id_ac18ad82_fk_workflow_";
ALTER TABLE "sentry_groupopenperiod" ADD CONSTRAINT "sentry_groupopenperi_group_id_f4411413_fk_sentry_gr" FOREIGN KEY ("group_id") REFERENCES "sentry_groupedmessage" ("id") DEFERRABLE INITIALLY DEFERRED NOT VALID;
ALTER TABLE "sentry_groupopenperiod" VALIDATE CONSTRAINT "sentry_groupopenperi_group_id_f4411413_fk_sentry_gr";
ALTER TABLE "sentry_groupopenperiod" ADD CONSTRAINT "sentry_groupopenperiod_project_id_5ef8bacc_fk_sentry_project_id" FOREIGN KEY ("project_id") REFERENCES "sentry_project" ("id") DEFERRABLE INITIALLY DEFERRED NOT VALID;
ALTER TABLE "sentry_groupopenperiod" VALIDATE CONSTRAINT "sentry_groupopenperiod_project_id_5ef8bacc_fk_sentry_project_id";
ALTER TABLE "sentry_groupopenperiod" ADD CONSTRAINT "sentry_groupopenperi_resolution_activity__cc5cc897_fk_sentry_ac" FOREIGN KEY ("resolution_activity_id") REFERENCES "sentry_activity" ("id") DEFERRABLE INITIALLY DEFERRED NOT VALID;
ALTER TABLE "sentry_groupopenperiod" VALIDATE CONSTRAINT "sentry_groupopenperi_resolution_activity__cc5cc897_fk_sentry_ac";
CREATE INDEX CONCURRENTLY "sentry_groupopenperiod_user_id_807f0152" ON "sentry_groupopenperiod" ("user_id");
CREATE INDEX CONCURRENTLY "sentry_groupopenperiod_data_condition_id_ac18ad82" ON "sentry_groupopenperiod" ("data_condition_id");
CREATE INDEX CONCURRENTLY "sentry_groupopenperiod_group_id_f4411413" ON "sentry_groupopenperiod" ("group_id");
CREATE INDEX CONCURRENTLY "sentry_groupopenperiod_project_id_5ef8bacc" ON "sentry_groupopenperiod" ("project_id");
CREATE INDEX CONCURRENTLY "sentry_groupopenperiod_resolution_activity_id_cc5cc897" ON "sentry_groupopenperiod" ("resolution_activity_id"); |
Codecov ReportAll modified and coverable lines are covered by tests ✅ ✅ All tests successful. No failed tests found. Additional details and impacted files@@ Coverage Diff @@
## master #87813 +/- ##
===========================================
+ Coverage 33.09% 87.77% +54.67%
===========================================
Files 8433 9982 +1549
Lines 470146 564343 +94197
Branches 22274 22166 -108
===========================================
+ Hits 155608 495328 +339720
+ Misses 314103 68599 -245504
+ Partials 435 416 -19 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought the plan here was to use activity to figure this all out?
Will this end up creating an extra row for each group that is created?
src/sentry/models/groupopenperiod.py
Outdated
data_condition = FlexibleForeignKey( | ||
"workflow_engine.DataCondition", null=True, on_delete=models.SET_NULL | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What will this be used for?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we'll need this for the short-term to continue support existing Incident-related endpoints while we give users a heads up and time to make any changes. We can remove the column when we remove those endpoints.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't really follow what we're using it for though, how are we joining here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The longer writeup is here but basically we will be updating the existing rule, alert rule, and incident serializers to read from the new ACI tables as much as possible but the main sticking point is that we need to continue returning the correct IDs for the aforementioned models.
For this specifically, the one additional piece of tricky data is the incident status
returned in the serializer response here. The only way I've been able to come up with us recreating this (outside of temporarily duplicating the column on this model) is to have a FK to DataCondition
so we can infer the status
based on the data condition (for example, a data condition with a condition result of DetectorPriorityLevel.HIGH
is the equivalent to a critical trigger today).
I'm completely open to other ideas btw
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Discussed in slack and we should be able to use GroupOpenPeriod
-> Group
-> Group.priority
or GroupOpenPeriod
-> Activity
(type=SET_PRIORITY
) instead of the FK
src/sentry/models/groupopenperiod.py
Outdated
date_started = models.DateTimeField(default=timezone.now) | ||
date_ended = models.DateTimeField(null=True) | ||
|
||
data: models.Field[dict[str, Any] | None, dict[str, Any]] = GzippedDictField(null=True) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you need to store values that are pickled? Generally I wouldn't recommend adding more fields like this. Pickled objects in the database is fragile. You could use models.JsonField
instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
gotcha, updated to models.JsonField
This PR has a migration; here is the generated SQL for --
-- Create model GroupOpenPeriod
--
CREATE TABLE "sentry_groupopenperiod" ("id" bigint NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY, "user_id" bigint NULL, "date_started" timestamp with time zone NOT NULL, "date_ended" timestamp with time zone NULL, "data" jsonb NOT NULL, "data_condition_id" bigint NULL, "group_id" bigint NOT NULL, "project_id" bigint NOT NULL, "resolution_activity_id" bigint NULL);
ALTER TABLE "sentry_groupopenperiod" ADD CONSTRAINT "sentry_groupopenperi_data_condition_id_ac18ad82_fk_workflow_" FOREIGN KEY ("data_condition_id") REFERENCES "workflow_engine_datacondition" ("id") DEFERRABLE INITIALLY DEFERRED NOT VALID;
ALTER TABLE "sentry_groupopenperiod" VALIDATE CONSTRAINT "sentry_groupopenperi_data_condition_id_ac18ad82_fk_workflow_";
ALTER TABLE "sentry_groupopenperiod" ADD CONSTRAINT "sentry_groupopenperi_group_id_f4411413_fk_sentry_gr" FOREIGN KEY ("group_id") REFERENCES "sentry_groupedmessage" ("id") DEFERRABLE INITIALLY DEFERRED NOT VALID;
ALTER TABLE "sentry_groupopenperiod" VALIDATE CONSTRAINT "sentry_groupopenperi_group_id_f4411413_fk_sentry_gr";
ALTER TABLE "sentry_groupopenperiod" ADD CONSTRAINT "sentry_groupopenperiod_project_id_5ef8bacc_fk_sentry_project_id" FOREIGN KEY ("project_id") REFERENCES "sentry_project" ("id") DEFERRABLE INITIALLY DEFERRED NOT VALID;
ALTER TABLE "sentry_groupopenperiod" VALIDATE CONSTRAINT "sentry_groupopenperiod_project_id_5ef8bacc_fk_sentry_project_id";
ALTER TABLE "sentry_groupopenperiod" ADD CONSTRAINT "sentry_groupopenperi_resolution_activity__cc5cc897_fk_sentry_ac" FOREIGN KEY ("resolution_activity_id") REFERENCES "sentry_activity" ("id") DEFERRABLE INITIALLY DEFERRED NOT VALID;
ALTER TABLE "sentry_groupopenperiod" VALIDATE CONSTRAINT "sentry_groupopenperi_resolution_activity__cc5cc897_fk_sentry_ac";
CREATE INDEX CONCURRENTLY "sentry_groupopenperiod_user_id_807f0152" ON "sentry_groupopenperiod" ("user_id");
CREATE INDEX CONCURRENTLY "sentry_groupopenperiod_data_condition_id_ac18ad82" ON "sentry_groupopenperiod" ("data_condition_id");
CREATE INDEX CONCURRENTLY "sentry_groupopenperiod_group_id_f4411413" ON "sentry_groupopenperiod" ("group_id");
CREATE INDEX CONCURRENTLY "sentry_groupopenperiod_project_id_5ef8bacc" ON "sentry_groupopenperiod" ("project_id");
CREATE INDEX CONCURRENTLY "sentry_groupopenperiod_resolution_activity_id_cc5cc897" ON "sentry_groupopenperiod" ("resolution_activity_id"); |
It was, but we'll be needing open periods in multiple places and as something we can easily query for the issue stream, the issue details graph and the datepicker in issue details. We'll also need the open periods to support existing Incident APIs. With all of that, it makes more sense to be able to query the lastest open period and update it as needed, and this should give us more nuanced info for each open period as we built it out.
Yea it will -- it's not ideal given we have grouphistory and activity which both serve similar purposes but this feels like the cleanest way to support open periods more natively without having to query and recalculate open periods multiple times. |
This PR has a migration; here is the generated SQL for --
-- Create model GroupOpenPeriod
--
CREATE TABLE "sentry_groupopenperiod" ("id" bigint NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY, "user_id" bigint NULL, "date_started" timestamp with time zone NOT NULL, "date_ended" timestamp with time zone NULL, "data" jsonb NOT NULL, "group_id" bigint NOT NULL, "project_id" bigint NOT NULL, "resolution_activity_id" bigint NULL);
ALTER TABLE "sentry_groupopenperiod" ADD CONSTRAINT "sentry_groupopenperi_group_id_f4411413_fk_sentry_gr" FOREIGN KEY ("group_id") REFERENCES "sentry_groupedmessage" ("id") DEFERRABLE INITIALLY DEFERRED NOT VALID;
ALTER TABLE "sentry_groupopenperiod" VALIDATE CONSTRAINT "sentry_groupopenperi_group_id_f4411413_fk_sentry_gr";
ALTER TABLE "sentry_groupopenperiod" ADD CONSTRAINT "sentry_groupopenperiod_project_id_5ef8bacc_fk_sentry_project_id" FOREIGN KEY ("project_id") REFERENCES "sentry_project" ("id") DEFERRABLE INITIALLY DEFERRED NOT VALID;
ALTER TABLE "sentry_groupopenperiod" VALIDATE CONSTRAINT "sentry_groupopenperiod_project_id_5ef8bacc_fk_sentry_project_id";
ALTER TABLE "sentry_groupopenperiod" ADD CONSTRAINT "sentry_groupopenperi_resolution_activity__cc5cc897_fk_sentry_ac" FOREIGN KEY ("resolution_activity_id") REFERENCES "sentry_activity" ("id") DEFERRABLE INITIALLY DEFERRED NOT VALID;
ALTER TABLE "sentry_groupopenperiod" VALIDATE CONSTRAINT "sentry_groupopenperi_resolution_activity__cc5cc897_fk_sentry_ac";
CREATE INDEX CONCURRENTLY "sentry_groupopenperiod_user_id_807f0152" ON "sentry_groupopenperiod" ("user_id");
CREATE INDEX CONCURRENTLY "sentry_groupopenperiod_group_id_f4411413" ON "sentry_groupopenperiod" ("group_id");
CREATE INDEX CONCURRENTLY "sentry_groupopenperiod_project_id_5ef8bacc" ON "sentry_groupopenperiod" ("project_id");
CREATE INDEX CONCURRENTLY "sentry_groupopenperiod_resolution_activity_id_cc5cc897" ON "sentry_groupopenperiod" ("resolution_activity_id"); |
This PR has a migration; here is the generated SQL for --
-- Creates extension btree_gist
--
CREATE EXTENSION IF NOT EXISTS "btree_gist";
--
-- Create model GroupOpenPeriod
--
CREATE TABLE "sentry_groupopenperiod" ("id" bigint NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY, "date_updated" timestamp with time zone NOT NULL, "date_added" timestamp with time zone NOT NULL, "user_id" bigint NULL, "date_started" timestamp with time zone NOT NULL, "date_ended" timestamp with time zone NULL, "data" jsonb NOT NULL, "group_id" bigint NOT NULL, "project_id" bigint NOT NULL, "resolution_activity_id" bigint NULL, CONSTRAINT "exclude_open_period_overlap" EXCLUDE USING GIST ((TSTZRANGE("date_started", "date_ended", '[)')) WITH &&));
ALTER TABLE "sentry_groupopenperiod" ADD CONSTRAINT "sentry_groupopenperi_group_id_f4411413_fk_sentry_gr" FOREIGN KEY ("group_id") REFERENCES "sentry_groupedmessage" ("id") DEFERRABLE INITIALLY DEFERRED NOT VALID;
ALTER TABLE "sentry_groupopenperiod" VALIDATE CONSTRAINT "sentry_groupopenperi_group_id_f4411413_fk_sentry_gr";
ALTER TABLE "sentry_groupopenperiod" ADD CONSTRAINT "sentry_groupopenperiod_project_id_5ef8bacc_fk_sentry_project_id" FOREIGN KEY ("project_id") REFERENCES "sentry_project" ("id") DEFERRABLE INITIALLY DEFERRED NOT VALID;
ALTER TABLE "sentry_groupopenperiod" VALIDATE CONSTRAINT "sentry_groupopenperiod_project_id_5ef8bacc_fk_sentry_project_id";
ALTER TABLE "sentry_groupopenperiod" ADD CONSTRAINT "sentry_groupopenperi_resolution_activity__cc5cc897_fk_sentry_ac" FOREIGN KEY ("resolution_activity_id") REFERENCES "sentry_activity" ("id") DEFERRABLE INITIALLY DEFERRED NOT VALID;
ALTER TABLE "sentry_groupopenperiod" VALIDATE CONSTRAINT "sentry_groupopenperi_resolution_activity__cc5cc897_fk_sentry_ac";
CREATE INDEX CONCURRENTLY "sentry_groupopenperiod_user_id_807f0152" ON "sentry_groupopenperiod" ("user_id");
CREATE INDEX CONCURRENTLY "sentry_groupopenperiod_group_id_f4411413" ON "sentry_groupopenperiod" ("group_id");
CREATE INDEX CONCURRENTLY "sentry_groupopenperiod_project_id_5ef8bacc" ON "sentry_groupopenperiod" ("project_id");
CREATE INDEX CONCURRENTLY "sentry_groupopenperiod_resolution_activity_id_cc5cc897" ON "sentry_groupopenperiod" ("resolution_activity_id");
CREATE INDEX CONCURRENTLY "sentry_grou_group_i_4bffd0_idx" ON "sentry_groupopenperiod" ("group_id", "date_started"); |
date_started = models.DateTimeField(default=timezone.now) | ||
date_ended = models.DateTimeField(null=True) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want to guard against overlapping open periods?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TIL about ExclusionConstraint
- not quite sure if I've set it up right
models.Index(fields=("group", "date_started")), | ||
) | ||
constraints = ( | ||
ExclusionConstraint( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if this extension is actually installed, so we should do https://docs.djangoproject.com/en/5.1/ref/contrib/postgres/operations/#django.contrib.postgres.operations.BtreeGistExtension
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm, thanks!
Adds a new table
GroupOpenPeriod
to track the times an issue is open, i.e. having a status that is not resolved. This will be used for detector-based issues in place of events. For example, instead of relying on incidents, open periods will be used to determine the start and end of a metric alert firing for metric issues.spec