Consolidating Sentry Cron Check‑ins & Adding Dynamic Inputs to GitHub Actions Workflows in content‑automation
TL;DR: I refactored the four separate Sentry cron check‑ins into a single monitor and exposed --lang/--repo as workflow_dispatch inputs for the Bluesky workflow. The changes cut CI noise, made the pipelines configurable at run‑time, and forced me to rewrite a broken Groq‑AI integration that was crashing the content generator.
The Problem
Our content‑automation repo runs four daily GitHub Actions workflows:
devto-daily.ymlbluesky-daily.ymldaily-content.ymlweekly-newsletter.yml
Each workflow performed its own Sentry “cron check‑in” using the sentry-cli command. After a Groq model deprecation (issue #63) broke every AI‑powered content generation step, the CI started spamming Sentry with dozens of failing check‑ins per day. The noise flooded our Sentry dashboard, making it impossible to spot real alerts.
Error snapshot from a failing run:
Error: Groq model "llama2" is deprecated (see https://groq.com/docs/models)
Traceback (most recent call last):
File "src/content_generator.py", line 42, in generate
response = client.query(model="llama2", prompt=prompt)
AttributeError: 'GroqClient' object has no attribute 'query'
Besides the AI failure, the duplicated Sentry calls added ~30 seconds to each workflow and made troubleshooting harder.
What I Tried First
My first instinct was to disable the Sentry checks in the failing workflows (devto-daily.yml and bluesky-daily.yml) and re‑enable them after fixing the Groq issue. I added a quick if: false guard around the sentry-cli step:
- name: Sentry cron check‑in
if: false
run: sentry-cli monitor check-in --monitor slug:devto-daily
That silenced the noise, but it also removed the health signal for the other three workflows. I quickly realized that turning off monitoring globally was a bad trade‑off, especially when the Groq bug would be fixed later and we’d have to remember to re‑enable the steps.
The Implementation
1. Consolidate All Cron Check‑ins into a Single Sentry Monitor
I created a new Sentry monitor called content-automation-cron and rewrote each workflow to call the same monitor. The sentry-cli command now lives in a reusable composite action (.github/actions/sentry-checkin/action.yml) to avoid duplication.
File: .github/actions/sentry-checkin/action.yml
name: "Sentry Cron Check‑in"
description: "Report a successful cron run to a single Sentry monitor"
inputs:
monitor_slug:
description: "Sentry monitor slug"
required: true
runs:
using: "composite"
steps:
- name: Install sentry-cli
run: npm i -g @sentry/cli
- name: Check‑in
run: |
sentry-cli monitor check-in \
--monitor ${{ inputs.monitor_slug }} \
--status ok \
--env ${{ env.SENTRY_ENVIRONMENT }}
Now each workflow references this action:
# .github/workflows/devto-daily.yml
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
# … other steps …
- uses: ./.github/actions/sentry-checkin
with:
monitor_slug: content-automation-cron
The same snippet appears in bluesky-daily.yml, daily-content.yml, and weekly-newsletter.yml. The result: one monitor, four check‑ins, which Sentry aggregates automatically. The dashboard now shows a single “Cron health” chart instead of four noisy streams.
2. Expose --lang and --repo as workflow_dispatch Inputs
The Bluesky workflow needed to generate posts in multiple languages and for different repos. Previously I hard‑coded the values in the YAML, which forced a new commit for every variation.
I added two inputs to bluesky-daily.yml:
# .github/workflows/bluesky-daily.yml
on:
schedule:
- cron: '0 6 * * *' # every day at 06:00 UTC
workflow_dispatch:
inputs:
lang:
description: 'Language code (en|es)'
required: true
default: 'en'
repo:
description: 'Target repo slug (e.g., albaida-tickets)'
required: true
default: 'albaida-tickets'
Inside the job, I forward those inputs to the Python script:
- name: Generate Bluesky posts
run: |
python src/content_generator.py \
--lang ${{ github.event.inputs.lang }} \
--repo ${{ github.event.inputs.repo }}
Now I can trigger a manual run from the Actions UI with any language/repo combination without touching code.
3. Add --theirs Auto‑Resolve Fallback for Merge Conflicts
When the devto and bluesky commit steps tried to push generated markdown files, occasional merge conflicts caused the jobs to fail. I added a fallback that automatically resolves using the --theirs strategy:
- name: Commit generated content
run: |
git add .
git commit -m "auto: generate ${{ github.event.inputs.lang }} content"
continue-on-error: true
- name: Resolve conflicts (theirs)
if: failure()
run: |
git merge -X theirs origin/main
git push origin HEAD:${{ github.ref }}
This kept the pipeline alive while still surfacing the conflict in the PR comments for later review.
4. Add Concurrency with cancel-in-progress
To avoid overlapping runs (especially after the weekly newsletter schedule changed), I applied the concurrency group from PR #66:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
All four workflows now share this block, ensuring that a new run aborts any previous one still executing.
5. Fix the Groq Model Deprecation
The real blocker was the AI model. Groq announced the deprecation of llama2 on 2026‑08‑16 (issue #63). I updated src/content_generator.py to use the new mixtral-8x7b model and added a fallback logger that prints the raw response when JSON parsing fails.
python
# src/content_generator.py
import os, json, logging
from groq import GroqClient
client = GroqClient(api_key=os.getenv("GROQ_API_KEY"))
def generate(prompt: str, model: str = "mixtral-8x
---
*Part of my [Build in Public](https://dev.to/zaerohell) series — sharing the real process of building SaaS projects from Playa del Carmen, México.*
*Repo: `zaerohell/content-automation` · 2026-10-01*
\#playadev #buildinpublic
Top comments (0)