Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 114 additions & 0 deletions src/firetower/incidents/hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -761,6 +761,119 @@ def _create_troubleshooting_doc(incident: Incident, channel_id: str) -> None:
).delete()


def _create_postmortem_doc(incident: Incident, channel_id: str) -> None:
notion = None
page = None
try:
if not NotionService.is_configured():
logger.info(
"Notion not configured, skipping postmortem doc for incident %s",
incident.id,
)
return

notion = NotionService.from_settings()
if not notion:
return

if incident.is_private:
logger.info("Skipping postmortem doc for private incident %s", incident.id)
return

with transaction.atomic():
link, created = ExternalLink.objects.select_for_update().get_or_create(
incident=incident,
type=ExternalLinkType.NOTION,
defaults={"url": ""},
)
if not created:
if link.url:
logger.info(
"Incident %s already has a postmortem doc, skipping",
incident.id,
)
else:
logger.info(
"Incident %s postmortem doc creation already in progress, skipping",
incident.id,
)
return
Comment thread
cursor[bot] marked this conversation as resolved.

incident_url = _build_incident_url(incident)
captain_email = incident.captain.email if incident.captain else None
page = notion.create_postmortem_page(
incident_number=incident.incident_number,
incident_title=incident.title,
incident_url=incident_url,
incident_date=incident.created_at,
severity=incident.severity,
captain_email=captain_email,
)
if not page or not page.get("url"):
logger.error(
"Postmortem doc creation returned no URL for %s",
incident.incident_number,
)
ExternalLink.objects.filter(
incident=incident,
type=ExternalLinkType.NOTION,
url="",
).delete()
return

orphan_page_id = None
try:
with transaction.atomic():
link = ExternalLink.objects.select_for_update().get(
incident=incident,
type=ExternalLinkType.NOTION,
)
if link.url:
logger.warning(
"Race condition: concurrent call already created postmortem doc for %s",
incident.incident_number,
)
orphan_page_id = page["id"]
else:
link.url = page["url"]
link.save(update_fields=["url"])
except ExternalLink.DoesNotExist:
logger.warning(
"Placeholder deleted before postmortem URL could be saved for %s",
incident.incident_number,
)
notion.archive_page(page["id"])
return

if orphan_page_id:
notion.archive_page(orphan_page_id)
return

try:
_slack_service.add_bookmark(channel_id, "Postmortem Doc", page["url"])
except Exception:
logger.exception(
"Failed to add postmortem doc bookmark for %s",
incident.incident_number,
)
except Exception:
logger.exception("Failed to create postmortem doc for incident %s", incident.id)
if notion and page and page.get("id"):
try:
notion.archive_page(page["id"])
except Exception:
logger.exception(
"Failed to archive orphaned Notion page %s for incident %s",
page["id"],
incident.id,
)
ExternalLink.objects.filter(
incident=incident,
type=ExternalLinkType.NOTION,
url="",
).delete()
Comment thread
sentry[bot] marked this conversation as resolved.


def decorate_incident_channel(
ctx: ChannelSetupContext,
slack_service: SlackService,
Expand Down Expand Up @@ -1262,6 +1375,7 @@ def on_incident_created(incident: Incident) -> None:
# appears first in the channel.
_create_datadog_notebook(incident, channel_id)
_create_troubleshooting_doc(incident, channel_id)
_create_postmortem_doc(incident, channel_id)
Comment thread
github-actions[bot] marked this conversation as resolved.

try:
create_linear_parent_issue(incident, channel_id=channel_id)
Expand Down
Loading
Loading