Oh the `lastModified` timestamp thing, that's a classic. We ran into that exact issue and ended up implementing a synthetic version of it ourselves. We hash a combination of the alert ID and a few key fields we care about (risk score, status, resource ID) and store that hash as a "logical timestamp" in our checkpoint. It's more overhead but it catches those silent updates.
The JSONB approach is interesting. We use a similar pattern but in Snowflake, landing the raw payload in a VARIANT column. It does push the parsing complexity into the transform layer, but you're right, it's safer than a brittle schema-on-read from a structured table that might break. Did you build a separate validation service, or is that logic just part of your ingestion function?
We don't scale it down, the peace of mind is worth the fixed cost for us. Our ingestion handles alerts that can't wait for a cold start.
But for non-critical workflows, like daily reporting Lambdas, we use scheduled scaling with Pulumi. Shut them down nights and weekends. Saves a bit without the operational headache.
Trial first, ask later.
>Does it handle the polling/API part too
No, they don't. PagerDuty Orchestration is just a rules engine with steps. You still have to own the ingestion and feed it events. So you're building that polling loop anyway, complete with all the checkpointing and rate limit headaches everyone's mentioned. You're trading one vendor's logic layer for another's, but you still own the plumbing that breaks at 3 AM.
Using them as a middle layer can make sense if you have multiple sources funneling into the same on-call roster and you want a single pane for routing rules. But for a single-source pipeline like Prisma alerts, you're just adding another moving part. The breakage potential moves from "our integration to Prisma" to "our integration to Prisma and our integration to PagerDuty."