Résolue

Django + stripe : gestion des erreurs

# Stripe # Optimisation # Django

Gabriel Trouvé

Mentor

Re Bonjour ! :)

Code

WebHook

@csrf_exempt
def stripe_webhook(request):
    # ./stripe listen --forward-to 127.0.0.1:8000/spa/stripe-webhook/
    payload = request.body
    sig_header = request.META['HTTP_STRIPE_SIGNATURE']
    endpoint_secret = settings.ENDPOINT_KEY
    event = None

    try:
        event = stripe.Webhook.construct_event(
            payload, sig_header, endpoint_secret
        )
    except ValueError as e:
        # Invalid payload
        return HttpResponse(status=400)
    except stripe.error.SignatureVerificationError as e:
        # Invalid signature
        return HttpResponse(status=400)

    if event["type"] == "checkout.session.completed":
        data = event["data"]["object"]
        update_user(data)
        update_reservation(data)

    # Passed signature verification
    return HttpResponse(status=200)

Fonction update_user

def update_user(data):
    user: CustomUser = CustomUser.objects.get(email=data['customer_details']['email'])
    if not user.stripe_id:
        user.stripe_id = data["customer"]
        user.save()
    return user

Fonction update_reservation

def update_reservation(data):
    pk_reservation = data.get("metadata", {}).get("reservation_id")
    if pk_reservation:
        try:
            reservation = Reservation.objects.get(pk=pk_reservation)
            reservation.paid, reservation.paid_on = True, timezone.now()
            reservation.save()
            return reservation
        except ObjectDoesNotExist:
            pass
    return None

Ce que je souhaite optimiser

Je n'ai pas de problème ça fonctionne. Je récupère l'utilisateur, et avec les metadata que j'ai dans mon checkout je récupère ma réservation avec la PK.

Ici c'est davantage la gestion des erreurs avec try except dans un webhook. En général je pense me débrouiller. Mais là avec le webhook j'ai du mal à comment gérer les erreurs.
Est-ce que je fait mes fonctions sans aucun try except ? Par ce qu'en soit si l'utilisateur arrive au paiement c'est qu'il a choisi une réservation et donc le PK est bien là dans tous les cas.

Ou est-ce que c'est vraiment utilie de gérer des exceptions ? Le Webhook étant un peu à part dans le projet je suis méga hésitant lol...

Merci d'avance ! :)

Salut !

je pense que oui ça peut toujours être utile de gérer les erreurs.

  1. même si normalement l'utilisateur arrive au paiement avec une réservation valide, il peut toujours se passer quelque chose de "mal" =D.
    Par exemple, la réservation pourrait être supprimée entre le temps où l'utilisateur l'a choisie et le moment où le webhook est appelé, ou l'email de l'utilisateur pourrait être modifié par une intervention externe.

  2. en incluant des blocs try...except, tu te prépares à gérer des situations imprévues, et cela aide à éviter que ton webhook n'arrête soudainement de fonctionner pour des cas d'erreurs non anticipées.

  3. sil y a une erreur, il peut être utile de savoir ce qui s'est passé. Les exceptions peuvent être loggées pour que tu puisses les examiner plus tard.

n'hésites pas si pas clair ou si besoin d'une réponse "à la Thibault" =D.

Gabriel Trouvé

Mentor

Merci PA !

Donc ici le risque c'est un ObjectDoesNotExist pour moi ?

Si jamais l'objet n'est pas trouvé, sachant que la réservation est payée tu le gères comment toi par exemple ?

Salut !

oui, typiquement, ObjectDoesNotExist est l'une des erreurs que tu pourrais avoir si la réservation n'est pas trouvée dans la base de données.

Si ça se produit, tu dois d'abord te demander "quel est l'impact pour l'utilisateur et pour le système ?" Si la réservation est payée mais que la référence n'existe plus, ça peut signifier que ton utilisateur est débité sans avoir sa réservation confirmée... oops =D.

Déjà tu peux logger l'erreur:

...

def update_reservation(data):
    pk_reservation = data.get("metadata", {}).get("reservation_id")
    if pk_reservation:
        try:
            reservation = Reservation.objects.get(pk=pk_reservation)
            reservation.paid, reservation.paid_on = True, timezone.now()
            reservation.save()
            return reservation
        except Reservation.DoesNotExist as e:
            # Log l'erreur avec le niveau 'error'.
            # dans ton logge run truc du genre: (f"Réservation non trouvée pour le PK {pk_reservation}: {e}")
    return None

En fonction de la façon dont tu gères les incidents, tu pourrais avoir un système d'alerte qui notifie l'équipe en cas de problèmes critiques.

Tu pourrais envoyer un email à l'utilisateur (i lme semble que tu sais faire ça déjà =D) pour l'informer d'une complication et dire que l'équipe s'occupe de résoudre.

si le webhook peut être rejoué, tu pourrais envisager d'avoir une action de récupération qui permettrait de traiter de nouveau la requête une fois le problème résolu.

Donc oui c'est une bonne idée de gérer les erreurs. Voilà j'espère que ça t'aide.

Gabriel Trouvé

Mentor

Oui je fais faire un ObjectDoesNotExist et faire un log.

Et dans mon système de SAV j'enregistre les messages en BDD en envoyant un mail au webmaster.

Donc.... je vais créer un ticket automatique pour ce cas là ! :)

Merci PA tu m'as donné une super idée ! Je vais pouvoir jouer avec mon modèle SAV du coup dans le except ! :)

Ah ah content de pouvoir t'aider =D. Montre nous tout ça quand ça sort du four =D.

Inscris-toi

(c'est gratuit !)

Inscris-toi

Tu dois créer un compte pour participer aux discussions.

Créer un compte

Rechercher sur le site

Formulaire de contact

Inscris-toi à Docstring

Pour commencer ton apprentissage.

Tu as déjà un compte ? Connecte-toi.