Modèles d'intégration Slack pour les alertes et les workflows
Slack est une interface utilisateur de flux de travail et une couche de livraison d'alertes.
Les intégrations Slack semblent trompeusement faciles car vous pouvez publier un message en une seule requête HTTP. La partie intéressante commence lorsque vous souhaitez que Slack soit interactif et fiable.

Cette analyse approfondie traite Slack comme trois surfaces d’intégration distinctes :
- Un puits de notification pour les alertes unidirectionnelles via des webhooks entrants.
- Un moteur de flux de travail via le Workflow Builder et des étapes de flux de travail personnalisées.
- Une interface d’événements via les boutons Block Kit, les commandes slash et les charges utiles d’action.
Cette page décrit comment les systèmes franchissent la frontière vers une interface utilisateur partagée qui peut également émettre des événements vers votre architecture, et non sur la philosophie des alertes. Pour la stratégie et le routage des alertes, consultez Conception de systèmes d’alerte modernes pour les équipes d’observabilité.
Lecture connexe :
- Les plateformes de chat comme interfaces système dans les systèmes modernes
- Modèle d’intégration Discord pour les alertes et les boucles de contrôle
- Conception de systèmes d’alerte modernes pour les équipes d’observabilité
Cadrage canonique et placement dans les modèles d’intégration
Slack n’est pas seulement l’endroit où les alertes vont mourir. Bien utilisé, Slack devient une interface système où les messages sont des artefacts avec état et où les interactions utilisateur sont des événements.
Cette page est placée de manière canonique sous /app-architecture/integration-patterns/slack/ car la question principale n’est pas “devons-nous alerter” mais “quel est le contrat entre notre système et Slack”.
Si votre solution nécessite l’un des éléments suivants, vous êtes dans le domaine des modèles d’intégration, et non dans celui de la simple notification :
- Une boucle de décision, où une approbation humaine déclenche une action.
- Un flux de travail, où Slack collecte du contexte et déclenche des étapes.
- Une boucle d’événements, où Slack émet des actions auxquelles votre système s’abonne.
La plateforme Slack soutient intentionnellement à la fois la messagerie unidirectionnelle et l’interaction bidirectionnelle via des URL de demande et des charges utiles d’interaction. Les webhooks entrants sont une méthode de premier ordre pour publier des charges utiles JSON, y compris les éléments de construction Block Kit, vers un canal (Envoi de messages à l’aide de webhooks entrants). L’interactivité est renvoyée à votre application sous forme de requêtes HTTP POST vers une URL de demande configurée, et ces charges utiles sont encodées en formulaire avec un champ de charge utile JSON (Gestion des interactions utilisateur).
Slack en tant que puits de notification
Les webhooks entrants sont le chemin le plus rapide vers la valeur pour les alertes et les mises à jour de statut. Un webhook est une URL unique liée à une installation d’application, et vous POSTEZ un message JSON vers celui-ci (Envoi de messages à l’aide de webhooks entrants).
Opinion : les webhooks sont un excellent choix par défaut lorsque vous souhaitez des messages “envoyer et oublier” et que vous n’avez pas besoin que Slack soit une surface de contrôle. Les webhooks sont également un excellent moyen de découpler votre onboarding de votre architecture d’application finale.
Slack en tant que moteur de flux de travail
Le Workflow Builder existe car le chat est l’endroit où le travail se fait réellement. Les flux de travail peuvent être simples ou complexes et peuvent se connecter à des applications (Guide du Workflow Builder).
Les étapes de flux de travail personnalisées vous permettent d’exposer vos systèmes comme des blocs de construction réutilisables à l’intérieur du Workflow Builder (Étapes de flux de travail). C’est une forme d’intégration différente des bots dans les canaux. Cela rapproche votre intégration de “l’outillage dans Slack” plutôt que de “messages de l’extérieur”.
Opinion : si votre organisation pense déjà en termes de flux de travail et d’approbations, les étapes de flux de travail peuvent sembler plus natives que des bots sur mesure.
Slack en tant qu’interface d’événements
Block Kit transforme un message en une surface d’interface utilisateur (Block Kit). Les composants interactifs comme les boutons génèrent des charges utiles d’action, généralement des charges utiles block_actions, qui sont envoyées à votre application lorsqu’un utilisateur clique (charge utile block_actions).
Les boutons ont des identifiants explicites action_id et une valeur optionnelle, et doivent être hébergés à l’intérieur de blocs section ou actions (Élément de bouton). Lorsque vous concevez un message avec un bouton, vous concevez une source d’événements.
C’est là que des sujets FAQ comme la vérification des demandes, les scopes requis et les déclencheurs internes sûrs deviennent le centre de la conception.
Modèles d’architecture qui passent à l’échelle
Flux de webhook pour l’alerte unidirectionnelle
[service] -> [formatteur d'alerte] -> [webhook entrant Slack] -> [canal]
Les webhooks entrants acceptent des charges utiles JSON et prennent en charge les mises en page Block Kit (Envoi de messages à l’aide de webhooks entrants).
Lorsque la FAQ demande la méthode la plus rapide pour envoyer des alertes, c’est généralement celle-ci.
Flux courtier avec une file d’attente pour la fiabilité et la contre-pression
[services] -> [sujet de file d'attente] -> [expéditeur Slack] -> [API Slack]
| |
| +-> [gestionnaire de limite de débit]
+-> [file d'attente des lettres mortes]
Les limites de débit de Slack s’appliquent aux API basées sur HTTP, y compris les webhooks entrants, et Slack renvoie un HTTP 429 avec un en-tête Retry-After lorsque vous dépassez les limites (Limites de débit).
Opinion : si vous publiez des alertes directement depuis chaque service, le premier incident se transforme en une attaque de déni de service distribué contre votre propre intégration Slack. Un expéditeur derrière une file d’attente tend à être une architecture plus calme.
Modèle d’automatisation de flux de travail avec approbations
[alerte] -> [message Slack avec bouton] -> [clic sur le bouton]
-> [charge utile d'action] -> [gestionnaire d'approbation] -> [API interne] -> [mise à jour du message]
L’interactivité Slack nécessite de configurer une URL de demande et d’activer l’interactivité. Slack envoie des charges utiles d’interaction sous forme application/x-www-form-urlencoded avec un paramètre payload contenant du JSON, et vous devez répondre avec un HTTP 200 dans les 3 secondes (Gestion des interactions utilisateur).
C’est le modèle derrière l’élément de la FAQ concernant le déclenchement d’actions internes en toute sécurité.
Diagramme de flux d’interaction Slack

Webhook vs application et la mécanique d’implémentation
Bibliothèques recommandées
Go :
- slack-go/slack pour les structures Web API et Block Kit (repo slack-go/slack, docs pkg.go.dev)
Python :
- slack_sdk (SDK Slack Python) pour les clients Web API, les helpers de signature et l’infrastructure de reprise (docs SDK Slack Python, repo python-slack-sdk)
Approche webhook vs bot d’application
Une comparaison pratique :
| Capacité | Webhook entrant | Application Slack avec jeton de bot |
|---|---|---|
| Publier des messages | Oui | Oui |
| Publier des mises en page Block Kit | Oui | Oui |
| Recevoir les clics de boutons | Seulement si lié à une application avec interactivité | Oui |
| Commandes slash | Non | Oui |
| Étapes de flux de travail | Non | Oui |
| Surface de sécurité | Secret de l’URL du webhook | Jetons OAuth plus secret de signature |
| Meilleur ajustement | Alertes unidirectionnelles | Flux de travail, approbations, UI interactive |
Slack prend explicitement en charge les mises en page Block Kit avec des webhooks entrants (Envoi de messages à l’aide de webhooks entrants). L’interactivité est configurée par application et livrée à une URL de demande (Gestion des interactions utilisateur).
Opinion : les webhooks sont un excellent premier jalon, mais dès que vous voulez que Slack soit une surface de contrôle, vous construisez une application. Évitez de faire croire le contraire.
Scopes et permissions
Les scopes Slack définissent ce que votre application peut faire. Il existe une référence centrale de scopes et des pages de scope individuelles (Référence des scopes). Pour l’envoi de messages via l’API Web, chat:write est le scope canonique (scope chat:write).
Pour les commandes slash, vous avez généralement besoin du scope commands et d’une URL de demande de commande configurée (les commandes font partie des docs d’interactivité, et chaque commande a sa propre URL de demande) (Gestion des interactions utilisateur).
Note FAQ : la livraison de la charge utile du bouton n’est pas “un scope”, c’est un paramètre d’application. Votre application reçoit des charges utiles lorsque l’Interactivité est activée et que l’URL de demande est définie, mais la publication de mises à jour de messages nécessite généralement chat:write.
Limites de débit et reprises
Les limites de débit de Slack renvoient un HTTP 429 et incluent Retry-After en secondes, et cela s’applique aux API basées sur HTTP, y compris les webhooks entrants (Limites de débit).
En pratique :
- respecter Retry-After
- appliquer un backoff avec du jitter pour les 5xx transitoires
- centraliser la livraison Slack dans un expéditeur lorsque le volume augmente
Idempotence et déduplication
Slack s’attend à une accusé de réception pour les charges utiles d’interaction dans les 3 secondes, sinon les utilisateurs voient une erreur et Slack peut réessayer la livraison selon la fonctionnalité (Gestion des interactions utilisateur). Pour l’API Events, Slack fournit explicitement des en-têtes de métadonnées de reprise x-slack-retry-num (API Events).
Même sans reprises explicites, les doublons se produisent car les utilisateurs double-cliquent et parce que les systèmes distribués réémettent. Si votre bouton déclenche une action interne, traitez les clics comme des événements au moins une fois et dédupliquez.
Une stratégie d’idempotence pratique pour les approbations :
- clé d’idempotence = team_id + channel_id + message_ts + action_id + user_id
- stocker la clé dans Redis avec un TTL correspondant à votre fenêtre de flux de travail
- l’API d’action interne impose également l’idempotence, pas seulement le gestionnaire Slack
Fondamentaux de sécurité et vérification des demandes
Slack signe les demandes vers votre serveur en utilisant votre secret de signature d’application. Slack envoie les en-têtes X-Slack-Signature et X-Slack-Request-Timestamp, et Slack recommande de rejeter les demandes plus anciennes de cinq minutes pour éviter les attaques par rejouabilité (Vérification des demandes provenant de Slack).
Deux pièges qui apparaissent dans les revues de code réelles :
- Vous devez calculer la signature sur le corps de la demande brut, avant l’analyse JSON ou le décodage de formulaire (Vérification des demandes provenant de Slack).
- Vous devez accuser réception des charges utiles interactives dans les 3 secondes, donc effectuez un travail lourd de manière asynchrone et utilisez response_url pour communiquer les résultats (Gestion des interactions utilisateur).
Le SDK Slack Python inclut un utilitaire de vérificateur de signature de demande dans le code et les docs (vérificateur de signature python-slack-sdk).
Conception de messages et d’interactions
Modèle de message d’alerte
Si vous voulez que Slack agisse comme une interface système, structurez vos messages pour que les décisions soient évidentes. Un modèle de message qui fonctionne bien à travers les équipes :
- titre
- gravité
- contexte
- indice d’action
- liens
Un modèle minimal :
titre : taux d’erreur de paiement élevé gravité : warn contexte : service=checkout env=prod region=us-east indice d’action : cliquez sur Approver restart pour déclencher un redémarrage sécurisé
Exemple de charge utile de webhook entrant
Les webhooks entrants acceptent des charges utiles JSON et peuvent inclure des mises en page riches en utilisant Block Kit (Envoi de messages à l’aide de webhooks entrants).
{
"text": "taux d'erreur de paiement élevé",
"blocks": [
{
"type": "header",
"text": { "type": "plain_text", "text": "taux d'erreur de paiement élevé" }
},
{
"type": "section",
"fields": [
{ "type": "mrkdwn", "text": "*gravité*\\nwarn" },
{ "type": "mrkdwn", "text": "*contexte*\\nservice=checkout env=prod region=us-east" }
]
},
{
"type": "section",
"text": { "type": "mrkdwn", "text": "*indice d'action*\\nCliquez sur Approver pour déclencher un redémarrage sécurisé." }
}
]
}
Conception de boutons et d’identifiants
Les boutons doivent être à l’intérieur de blocs section ou actions et inclure action_id et une valeur optionnelle (Élément de bouton). action_id est votre clé de routage. value est votre charge utile. Ensemble, ils constituent votre schéma d’événements.
Opinion : choisissez des valeurs action_id comme des points de terminaison d’API stables. Des noms comme “approve_restart” vieillissent mieux que “button_1”.
Gestion des charges utiles d’interaction, response_url et temporisation
Slack envoie des charges utiles d’interaction à votre URL de demande sous forme de données encodées en formulaire avec un paramètre payload contenant du JSON. La charge utile comprend un champ type définissant la source, tel que block_actions pour les clics de bouton (Gestion des interactions utilisateur, Charges utiles d’interaction).
Vous devez renvoyer un HTTP 200 dans les 3 secondes pour la réponse d’accusé de réception (Gestion des interactions utilisateur). Utilisez response_url pour mettre à jour le message d’origine ou répondre dans le canal ou dans un fil, et Slack limite l’utilisation de response_url à cinq fois dans les trente minutes (Gestion des interactions utilisateur).
Cette contrainte de temporisation est une contrainte de conception. Elle vous force à découpler “accuser réception” de “faire le travail”.
Modèles d’interaction adaptés à Slack
- Boutons dans Block Kit pour les approbations et la bifurcation.
- Commandes slash pour l’intention utilisateur explicite et les paramètres.
- Étapes de flux de travail pour des processus métier répétables dans le Workflow Builder (Étapes de flux de travail).
- Raccourcis et modaux lorsque vous avez besoin d’une entrée structurée, avec des contraintes trigger_id décrites dans les docs d’interactivité (Gestion des interactions utilisateur).
Exemples Go et Python
Note de l’éditeur : ceux-ci peuvent être divisés en pages d’exemple dédiées :
/app-architecture/integration-patterns/slack/go-example/app-architecture/integration-patterns/slack/python-example
Les exemples privilégient une chose qui maintient les systèmes stables :
- vérifier les signatures Slack
- accuser réception dans les trois secondes
- dédupliquer les actions
- déclencher une requête HTTP POST interne
- mettre à jour Slack optionnellement en utilisant response_url
Exemple Go : envoyer une alerte et gérer l’approbation de bouton
Prérequis :
- Application Slack avec Interactivité activée et URL de demande configurée (Gestion des interactions utilisateur).
- Jeton de bot avec le scope chat:write (scope chat:write).
- Un secret de signature pour la vérification des demandes (Vérification des demandes provenant de Slack).
package main
import (
"bytes"
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"io"
"log"
"net/http"
"net/url"
"os"
"strconv"
"strings"
"sync"
"time"
"github.com/slack-go/slack"
)
type BlockActionPayload struct {
Type string `json:"type"`
Team struct{ ID string `json:"id"` } `json:"team"`
User struct{ ID string `json:"id"` } `json:"user"`
Channel struct {
ID string `json:"id"`
} `json:"channel"`
Message struct {
Ts string `json:"ts"`
} `json:"message"`
ResponseURL string `json:"response_url"`
Actions []struct {
ActionID string `json:"action_id"`
Value string `json:"value"`
Type string `json:"type"`
} `json:"actions"`
}
type InternalAction struct {
Action string `json:"action"`
TeamID string `json:"team_id"`
ChannelID string `json:"channel_id"`
MessageTS string `json:"message_ts"`
UserID string `json:"user_id"`
Value string `json:"value"`
}
var (
// En production, stockez ceci dans Redis avec un TTL
seenMu sync.Mutex
seen = map[string]time.Time{}
ttl = 10 * time.Minute
)
func main() {
botToken := os.Getenv("SLACK_BOT_TOKEN")
signingSecret := os.Getenv("SLACK_SIGNING_SECRET")
channelID := os.Getenv("SLACK_CHANNEL_ID")
internalURL := os.Getenv("INTERNAL_API_URL")
listenAddr := os.Getenv("LISTEN_ADDR") // e.g. :8080
if botToken == "" || signingSecret == "" || channelID == "" || internalURL == "" || listenAddr == "" {
log.Fatal("variables d'environnement manquantes SLACK_BOT_TOKEN SLACK_SIGNING_SECRET SLACK_CHANNEL_ID INTERNAL_API_URL LISTEN_ADDR")
}
api := slack.New(botToken)
// Envoyer un message d'alerte avec un bouton d'approbation.
// Les boutons sont des éléments Block Kit interactifs avec action_id et value.
// Voir les docs d'élément de bouton Slack Block Kit.
blocks := slack.Blocks{
BlockSet: []slack.Block{
slack.NewHeaderBlock(slack.NewTextBlockObject("plain_text", "taux d'erreur de paiement élevé", false, false)),
slack.NewSectionBlock(
slack.NewTextBlockObject("mrkdwn", "*gravité*\\nwarn\\n*contexte*\\nservice=checkout env=prod", false, false),
nil,
nil,
),
slack.NewActionBlock(
"actions_1",
slack.NewButtonBlockElement("approve_restart", "restart", slack.NewTextBlockObject("plain_text", "Approuver le redémarrage", false, false)),
),
},
}
_, ts, err := api.PostMessage(channelID, slack.MsgOptionBlocks(blocks.BlockSet...))
if err != nil {
log.Fatalf("PostMessage a échoué : %v", err)
}
log.Printf("message d'alerte publié message_ts=%s", ts)
// Point de terminaison d'interactivité
http.HandleFunc("/slack/actions", func(w http.ResponseWriter, r *http.Request) {
rawBody, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, "échec de la lecture du corps", http.StatusBadRequest)
return
}
r.Body.Close()
// Vérifier la signature de la demande Slack sur le corps brut et le timestamp.
// Voir les docs de Slack sur la vérification des demandes.
if !verifySlackRequest(r.Header, rawBody, signingSecret) {
http.Error(w, "signature invalide", http.StatusUnauthorized)
return
}
// Slack envoie application/x-www-form-urlencoded avec payload=JSON
vals, err := url.ParseQuery(string(rawBody))
if err != nil {
http.Error(w, "mauvais corps de formulaire", http.StatusBadRequest)
return
}
payloadStr := vals.Get("payload")
if payloadStr == "" {
http.Error(w, "payload manquant", http.StatusBadRequest)
return
}
var p BlockActionPayload
if err := json.Unmarshal([]byte(payloadStr), &p); err != nil {
http.Error(w, "mauvais json de payload", http.StatusBadRequest)
return
}
// Accuser réception dans 3 secondes. Faites le vrai travail de manière asynchrone et utilisez response_url pour les mises à jour.
// Voir les docs d'interactivité de Slack sur la temporisation d'accusé de réception.
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(""))
go func() {
if p.Type != "block_actions" || len(p.Actions) == 0 {
return
}
a := p.Actions[0]
if a.ActionID != "approve_restart" {
return
}
// Dédupliquer les approbations
key := strings.Join([]string{p.Team.ID, p.Channel.ID, p.Message.Ts, p.User.ID, a.ActionID, a.Value}, "|")
if !tryOnce(key) {
return
}
req := InternalAction{
Action: "approve_restart",
TeamID: p.Team.ID,
ChannelID: p.Channel.ID,
MessageTS: p.Message.Ts,
UserID: p.User.ID,
Value: a.Value,
}
if err := postJSON(internalURL, req); err != nil {
log.Printf("action interne échouée : %v", err)
_ = replyViaResponseURL(p.ResponseURL, "action échouée, vérifiez les logs")
return
}
_ = replyViaResponseURL(p.ResponseURL, "approbation reçue, action interne déclenchée")
}()
})
log.Printf("écoute sur %s", listenAddr)
log.Fatal(http.ListenAndServe(listenAddr, nil))
}
func tryOnce(key string) bool {
now := time.Now()
seenMu.Lock()
defer seenMu.Unlock()
for k, t := range seen {
if now.Sub(t) > ttl {
delete(seen, k)
}
}
if _, ok := seen[key]; ok {
return false
}
seen[key] = now
return true
}
func verifySlackRequest(h http.Header, body []byte, signingSecret string) bool {
ts := h.Get("X-Slack-Request-Timestamp")
sig := h.Get("X-Slack-Signature")
if ts == "" || sig == "" {
return false
}
tsInt, err := strconv.ParseInt(ts, 10, 64)
if err != nil {
return false
}
// Rejeter les demandes plus anciennes de 5 minutes pour réduire le risque de rejouabilité.
if time.Since(time.Unix(tsInt, 0)) > 5*time.Minute {
return false
}
base := "v0:" + ts + ":" + string(body)
mac := hmac.New(sha256.New, []byte(signingSecret))
mac.Write([]byte(base))
sum := hex.EncodeToString(mac.Sum(nil))
expected := "v0=" + sum
return hmac.Equal([]byte(expected), []byte(sig))
}
func postJSON(url string, body any) error {
b, err := json.Marshal(body)
if err != nil {
return err
}
req, err := http.NewRequest(http.MethodPost, url, bytes.NewReader(b))
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/json")
c := &http.Client{Timeout: 5 * time.Second}
res, err := c.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
if res.StatusCode < 200 || res.StatusCode >= 300 {
return io.ErrUnexpectedEOF
}
return nil
}
func replyViaResponseURL(responseURL string, text string) error {
if responseURL == "" {
return nil
}
// response_url accepte les charges utiles JSON et peut poster éphémère par défaut.
b, _ := json.Marshal(map[string]string{
"text": text,
})
req, _ := http.NewRequest(http.MethodPost, responseURL, bytes.NewReader(b))
req.Header.Set("Content-Type", "application/json")
c := &http.Client{Timeout: 5 * time.Second}
res, err := c.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
return nil
}
Exemple Python : envoyer une alerte et gérer l’approbation de bouton
Prérequis :
- Application Slack avec Interactivité activée et URL de demande configurée (Gestion des interactions utilisateur).
- Jeton de bot avec le scope chat:write (scope chat:write).
- Secret de signature pour la vérification des demandes (Vérification des demandes provenant de Slack).
import os
import json
import time
import threading
import requests
from flask import Flask, request, make_response
from slack_sdk import WebClient
from slack_sdk.signature import SignatureVerifier
SLACK_BOT_TOKEN = os.environ["SLACK_BOT_TOKEN"]
SLACK_SIGNING_SECRET = os.environ["SLACK_SIGNING_SECRET"]
SLACK_CHANNEL_ID = os.environ["SLACK_CHANNEL_ID"]
INTERNAL_API_URL = os.environ["INTERNAL_API_URL"]
client = WebClient(token=SLACK_BOT_TOKEN)
verifier = SignatureVerifier(signing_secret=SLACK_SIGNING_SECRET)
app = Flask(__name__)
# En production, stockez ces éléments dans Redis
_seen = {}
_TTL_SECONDS = 600
def try_once(key: str) -> bool:
now = int(time.time())
expired = [k for k, t in _seen.items() if now - t > _TTL_SECONDS]
for k in expired:
_seen.pop(k, None)
if key in _seen:
return False
_seen[key] = now
return True
def post_internal_action(payload: dict) -> None:
requests.post(INTERNAL_API_URL, json=payload, timeout=5)
def reply_via_response_url(response_url: str, text: str) -> None:
if not response_url:
return
requests.post(response_url, json={"text": text}, timeout=5)
def send_alert_with_button() -> None:
blocks = [
{"type": "header", "text": {"type": "plain_text", "text": "taux d'erreur de paiement élevé"}},
{"type": "section", "text": {"type": "mrkdwn", "text": "*gravité*\\nwarn\\n*contexte*\\nservice=checkout env=prod"}},
{
"type": "actions",
"block_id": "actions_1",
"elements": [
{
"type": "button",
"text": {"type": "plain_text", "text": "Approuver le redémarrage"},
"action_id": "approve_restart",
"value": "restart"
}
]
}
]
# chat.postMessage nécessite le scope chat:write.
client.chat_postMessage(channel=SLACK_CHANNEL_ID, text="taux d'erreur de paiement élevé", blocks=blocks)
@app.post("/slack/actions")
def slack_actions():
raw_body = request.get_data() # Slack recommande de vérifier le corps brut avant l'analyse
if not verifier.is_valid_request(raw_body, request.headers):
return make_response("signature invalide", 401)
# Slack envoie application/x-www-form-urlencoded avec un champ payload contenant du JSON.
payload_str = request.form.get("payload", "")
if not payload_str:
return make_response("payload manquant", 400)
payload = json.loads(payload_str)
# Accuser réception dans 3 secondes. L'utilisateur Slack voit des erreurs si vous ne le faites pas.
# Voir les docs d'interactivité de Slack sur l'accusé de réception.
resp = make_response("", 200)
def work():
if payload.get("type") != "block_actions":
return
actions = payload.get("actions", [])
if not actions:
return
a = actions[0]
if a.get("action_id") != "approve_restart":
return
team_id = payload.get("team", {}).get("id", "")
channel_id = payload.get("channel", {}).get("id", "")
user_id = payload.get("user", {}).get("id", "")
message_ts = payload.get("message", {}).get("ts", "")
value = a.get("value", "")
key = "|".join([team_id, channel_id, message_ts, user_id, "approve_restart", value])
if not try_once(key):
return
internal_payload = {
"action": "approve_restart",
"team_id": team_id,
"channel_id": channel_id,
"message_ts": message_ts,
"user_id": user_id,
"value": value,
}
try:
post_internal_action(internal_payload)
reply_via_response_url(payload.get("response_url", ""), "approbation reçue, action interne déclenchée")
except Exception:
reply_via_response_url(payload.get("response_url", ""), "action échouée, vérifiez les logs")
threading.Thread(target=work, daemon=True).start()
return resp
if __name__ == "__main__":
send_alert_with_button()
app.run(host="0.0.0.0", port=int(os.getenv("PORT", "8080")))
Notes Ops : routage, UX, sécurité, liens et SEO
Quand utiliser Slack vs outils de page vs Discord
Cette page concerne la mécanique. Le routage est une stratégie. Pourtant, la frontière est facile à décrire.
| Canal | Meilleur pour | Mode de défaillance |
|---|---|---|
| PagerDuty ou équivalent | Impact utilisateur urgent nécessitant une réponse immédiate | Les gens dorment pendant Slack |
| Slack | Coordination, approbations, exécution de flux de travail | Bruit et fatigue de canal |
| Discord | Équipes qui vivent dans Discord, boucles de contrôle plus légères | Moins de structure de flux de travail d’entreprise |
Utilisez Slack lorsque vous voulez que la conversation et le flux de travail soient l’interface. Utilisez les outils de page lorsque l’alerte n’est pas optionnelle. Si vous équilibrez la conception d’interaction Slack contre les limites de service et les choix de persistance, cet aperçu de l’architecture d’application aide à placer cette décision dans le système plus large. Pour un modèle de routage plus profond, consultez Conception de systèmes d’alerte modernes pour les équipes d’observabilité. Pour une alternative d’intégration Discord, consultez Modèle d’intégration Discord pour les alertes et les boucles de contrôle.
Notes d’accessibilité et d’UX
- Mettez les alertes à fort volume dans leur propre canal et gardez la discussion humaine dans les fils.
- Utilisez les fils pour le contexte et les mises à jour par incident. response_url peut poster dans le canal et dans les fils lorsque thread_ts est fourni (Gestion des interactions utilisateur).
- Utilisez des réponses éphémères lors de l’accusé de réception des actions utilisateur pour éviter le spam de canal, mais rappelez-vous que la livraison éphémère n’est pas garantie et dépend de la session (chat.postEphemeral).
- Utilisez Block Kit Builder pour prototyper des mises en page rapidement (Block Kit).
- Si vous ajoutez des images, incluez un texte alternatif significatif là où c’est supporté et conservez une chute de texte en clair dans le champ text de niveau supérieur.
Checklist de sécurité
- Vérifiez chaque demande Slack entrante en utilisant les en-têtes de secret de signature et le corps brut (Vérification des demandes provenant de Slack).
- Rejetez les demandes avec des timestamps plus anciens de cinq minutes pour réduire le risque de rejouabilité (Vérification des demandes provenant de Slack).
- Gardez les jetons et les URLs de webhook dans un gestionnaire de secrets, jamais dans git.
- Utilisez des scopes OAuth de privilège minimum et faites tourner les secrets lorsque les gens changent de rôle (Référence des scopes).
- Authentifiez et autorisez l’API d’action interne séparément, ne traitez pas Slack comme une frontière d’authentification.
- Rendre les approbations idempotentes et dédupliquées.
- Journalisez les approbations d’une manière conviviale à l’audit, y compris l’équipe, le canal, le timestamp du message, l’utilisateur et l’action.
Conclusion
Slack est à son meilleur lorsque vous le traitez comme une frontière système, pas comme un puits de messages. Les webhooks entrants couvrent la livraison rapide d’alertes. Les applications plus l’interactivité transforment Slack en un moteur de flux de travail et une interface d’événements. Les parties difficiles sont la vérification de signature, les contraintes de temporisation, la déduplication et le choix de l’endroit où Slack s’insère dans votre modèle de routage d’alerte.
Liens suivants :