qq icon
QQIncomingWebhook icon
Pause icon

Human-in-the-loop approval with QQ notifications

Human-in-the-loop approval gate that pings an approver QQ group, pauses on Tencent Cloud IM, and posts the decision or expiry back to chat.

Categories
Business

Drive a human-in-the-loop approval gate that pings a Tencent Cloud IM / QQ approver group, pauses the workflow on a deep link to the Kestra Resume button, and posts the outcome (or an expiry notice) back to the same chat. This blueprint pairs io.kestra.plugin.tencent.qq.QQIncomingWebhook with io.kestra.plugin.core.flow.Pause so production deploys, data releases, or finance approvals never move forward without an explicit human decision, and the audit trail of who decided what lives in chat alongside the execution id.

How it works

  1. notify_pending_approval (io.kestra.plugin.tencent.qq.QQIncomingWebhook) posts a message to the QQ recipients in inputs.approver_recipients containing inputs.change_summary, inputs.requested_by, and a deep link to the Resume button built from inputs.kestra_ui_url and the execution id.
  2. wait_for_approval (io.kestra.plugin.core.flow.Pause) halts the run for pauseDuration: P2D with behavior: FAIL, waiting for an approver to resume it with the approved (BOOLEAN, defaults to false) and reason (STRING) onResume inputs.
  3. If the Pause times out, its errors block runs notify_expired, a second QQIncomingWebhook that posts a "request expired, no decision taken" message to the same group.
  4. notify_outcome (QQIncomingWebhook) posts the recorded decision back to the QQ group, rendering outputs.wait_for_approval.onResume.approved as APPROVED or REJECTED along with the supplied reason.
  5. pluginDefaults on io.kestra.plugin.tencent.qq inject the url and token once so every QQ call uses the same endpoint and credentials.

What you get

  • A fail-closed approval gate: approved defaults to false, so a careless Resume rejects rather than auto-approves.
  • Bounded waits via pauseDuration: P2D so executions never hang indefinitely.
  • Reliable delivery: critical notifications use timeout: PT30S and retry (constant, three attempts).
  • Correlation by execution id in every message, so concurrent approvals stay distinguishable.
  • Injection-safe payloads: every user-supplied string is concatenated and passed through | toJson.

Who it's for

  • Platform and SRE teams gating production deploys and infrastructure changes.
  • Data engineering teams approving releases, dbt promotions, or backfills.
  • Operations and finance teams that already coordinate on QQ or Tencent Cloud IM and want approvals next to the conversation, not in a separate ticket tool.

Why orchestrate this with Kestra

Tencent Cloud IM is a messaging API, not a workflow engine. It cannot pause a deploy pipeline, wait for an approver, retry a failed webhook, branch on the decision, or expire a stalled request. Kestra adds the missing control plane: declarative YAML for the whole approval flow, event triggers and Resume API to drive the gate from external systems, retries and timeouts on each notification, automatic expiry handling via the Pause errors block, and full execution lineage tying the chat message, the decision, and the downstream tasks to one execution id.

Prerequisites

  • A Tencent Cloud IM / QQ application with the REST API enabled and a valid UserSig signature.
  • The Tencent Cloud IM sendmsg REST endpoint URL for your SDKAppID (for example v4/openim/sendmsg).
  • One or more QQ group or user identifiers for the approver audience.
  • A reachable kestra_ui_url so the Resume deep link resolves for approvers.

Secrets

  • TENCENT_IM_URL: Tencent Cloud IM REST endpoint used to send messages, including your SDKAppID and admin identifier.
  • TENCENT_IM_TOKEN: Tencent Cloud IM authentication token or UserSig signature.

Quick start

  1. Add the TENCENT_IM_URL and TENCENT_IM_TOKEN secrets to your Kestra instance.
  2. Set approver_recipients to the QQ group or user identifiers of your approvers.
  3. Set kestra_ui_url to your Kestra base URL so the Resume link resolves.
  4. Deploy the flow and execute it; the approver group receives a pending-approval message with the deep link.
  5. Open the execution, click Resume, set approved and reason. The outcome message is sent to the same group. If no one acts within two days, the group receives the expiry notice instead.

How to extend

  • Wire the flow into a deploy pipeline by calling it as a Subflow from a parent CI/CD flow and gating the next stage on outputs.wait_for_approval.onResume.approved.
  • Replace the manual trigger with a webhook or event trigger (for example a GitHub release, a Kafka event, or a dbt run completion) so approvals start themselves.
  • Branch on the decision with io.kestra.plugin.core.flow.If to run a rollback, a Slack mirror message, or a ServiceNow change record on rejection.
  • Add Kestra EE RBAC to restrict who may resume executions; the Pause input records the decision, but RBAC enforces the access control.
  • Increase or decrease pauseDuration, or change behavior: FAIL to CANCEL for non-critical approvals.

Links

Share this Blueprint
See How

New to Kestra?

Use blueprints to kickstart your first workflows.