DEV Community

Roberto Luna
Roberto Luna

Posted on

Consolidating Sentry Cron Check‑ins & Adding Dynamic Inputs to GitHub Actions Workflows in **content‑automation**

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.yml
  • bluesky-daily.yml
  • daily-content.yml
  • weekly-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'
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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 }}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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'
Enter fullscreen mode Exit fullscreen mode

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 }}
Enter fullscreen mode Exit fullscreen mode

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 }}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Top comments (0)