Conseils et astuces
Ce document décrit les bonnes pratiques relatives à la conception, à la mise en œuvre, au test et au déploiement de fonctions Cloud Run.
Exactitude
Cette section décrit les bonnes pratiques générales relatives à la conception et à la mise en œuvre de fonctions Cloud Run.
Écrire des fonctions idempotentes
Vos fonctions devraient produire le même résultat même si elles sont appelées plusieurs fois. Vous pouvez ainsi relancer un appel si l'appel précédent a échoué au milieu de votre code. Pour plus d'informations, consultez la page Effectuer de nouvelles tentatives d'exécution des fonctions basées sur des événements.
Vérifier que les fonctions HTTP envoient une réponse HTTP
Si votre fonction est déclenchée par HTTP, n'oubliez pas d'envoyer une réponse HTTP, comme indiqué ci-dessous. À défaut, votre fonction peut s'exécuter jusqu'au délai d'inactivité. Dans ce cas, vous serez facturé pendant toute la durée définie. Les délais d'inactivité peuvent également provoquer un comportement imprévisible ou un démarrage à froid lors d'appels ultérieurs, ce qui entraîne une latence supplémentaire.
Node.js
Python
Go
Java
C#
Ruby
PHP
Ne pas démarrer les activités d'arrière-plan
L'activité d'arrière-plan désigne tout ce qui se produit après l'arrêt de votre fonction.
Un appel de fonction se termine une fois que la fonction renvoie ou signale la fin, par exemple en appelant l'argument callback
dans les fonctions basées sur des événements Node.js. Tout code exécuté après un arrêt concerté ne peut pas accéder au processeur et ne progresse pas.
Par ailleurs, lorsqu'un appel ultérieur est exécuté dans le même environnement, votre activité d'arrière-plan reprend, ce qui interfère avec le nouvel appel et peut entraîner un comportement inattendu et des erreurs difficiles à analyser. L'accès au réseau après l'arrêt d'une fonction entraîne généralement la réinitialisation des connexions (code d'erreur ECONNRESET
).
L'activité d'arrière-plan peut souvent être détectée dans les journaux d'appels individuels, en recherchant tout ce qui est enregistré à la suite de la ligne indiquant que l'appel est terminé. Elle peut parfois être enfouie plus profondément dans le code, notamment en présence d'opérations asynchrones telles que des rappels ou des timers. Examinez votre code pour vous assurer que toutes les opérations asynchrones se terminent avant d'arrêter la fonction.
Toujours supprimer les fichiers temporaires
Le stockage sur disque local dans le répertoire temporaire est un système de fichiers en mémoire. Les fichiers que vous écrivez consomment de la mémoire disponible pour votre fonction et persistent parfois entre les appels. Si vous ne supprimez pas explicitement ces fichiers, cela risque d'entraîner une erreur de mémoire insuffisante et un démarrage à froid ultérieur.
Pour voir la mémoire utilisée par une fonction individuelle, sélectionnez cette dernière dans la liste des fonctions de la console Google Cloud et choisissez le tracé d'utilisation de la mémoire.
N'essayez pas d'écrire hors du répertoire temporaire et veillez à utiliser des méthodes indépendantes de la plate-forme/de l'OS pour créer des chemins de fichiers.
Vous pouvez réduire les besoins en mémoire lors du traitement de fichiers plus volumineux à l'aide du pipeline. Par exemple, pour traiter un fichier sur Cloud Storage, créez un flux de lecture, transmettez-le via un processus basé sur le flux et écrivez le flux de sortie directement dans Cloud Storage.
Framework des fonctions
Lorsque vous déployez une fonction, le framework des fonctions est automatiquement ajouté en tant que dépendance, en utilisant sa dernière version en date. Pour vous assurer que les mêmes dépendances sont installées de manière cohérente dans différents environnements, nous vous recommandons d'épingler votre fonction à une version spécifique du framework des fonctions.
Pour ce faire, spécifiez la version que vous préférez dans le fichier de verrouillage approprié (par exemple, package-lock.json
pour Node.js ou requirements.txt
pour Python).
Outils
Cette section fournit des instructions sur l'utilisation des outils pour la mise en œuvre, le test et l'interaction avec les fonctions Cloud Run.
Développement local
Le déploiement des fonctions prend un peu de temps. Il est donc souvent plus rapide de tester le code de votre fonction localement.
Création de rapports d'erreur
Dans les langages qui utilisent le traitement des exceptions, ne lancez pas d'exceptions non interceptées, car elles forcent les démarrages à froid lors d'appels ultérieurs. Consultez le guide Error Reporting pour savoir comment signaler correctement les erreurs.
Ne pas fermer manuellement
La fermeture manuelle peut entraîner un comportement inattendu. Veuillez plutôt utiliser les idiomes spécifiques aux langages suivants :
Node.js
N'utilisez pas process.exit()
. Les fonctions HTTP doivent envoyer une réponse avec res.status(200).send(message)
, et les fonctions basées sur des événements se ferment une fois qu'elles renvoient une valeur (implicitement ou explicitement).
Python
N'utilisez pas sys.exit()
. Les fonctions HTTP doivent explicitement renvoyer une réponse sous forme de chaîne, et les fonctions basées sur des événements se ferment une fois qu'elles renvoient une valeur (implicitement ou explicitement).
Go
N'utilisez pas os.Exit()
. Les fonctions HTTP doivent explicitement renvoyer une réponse sous forme de chaîne, et les fonctions basées sur des événements se ferment une fois qu'elles renvoient une valeur (implicitement ou explicitement).
Java
N'utilisez pas System.exit()
. Les fonctions HTTP doivent envoyer une réponse avec response.getWriter().write(message)
, et les fonctions basées sur des événements se ferment une fois qu'elles renvoient une valeur (implicitement ou explicitement).
C#
N'utilisez pas System.Environment.Exit()
. Les fonctions HTTP doivent envoyer une réponse avec context.Response.WriteAsync(message)
, et les fonctions basées sur des événements se ferment une fois qu'elles renvoient une valeur (implicitement ou explicitement).
Ruby
N'utilisez ni exit()
, ni abort()
. Les fonctions HTTP doivent explicitement renvoyer une réponse sous forme de chaîne, et les fonctions basées sur des événements se ferment une fois qu'elles renvoient une valeur (implicitement ou explicitement).
PHP
N'utilisez ni exit()
, ni die()
. Les fonctions HTTP doivent explicitement renvoyer une réponse sous forme de chaîne, et les fonctions basées sur des événements se ferment une fois qu'elles renvoient une valeur (implicitement ou explicitement).
Utiliser Sendgrid pour envoyer des e-mails
Cloud Run Functions n'autorise pas les connexions sortantes sur le port 25. Vous ne pouvez donc pas établir de connexions non sécurisées avec un serveur SMTP. La méthode recommandée pour envoyer des e-mails consiste à utiliser SendGrid. Vous pouvez trouver d'autres options d'envoi d'e-mails dans le tutoriel Envoyer des e-mails depuis une instance pour Google Compute Engine.
Performance
Cette section décrit les bonnes pratiques relatives à l'optimisation des performances.
Utiliser les dépendances à bon escient
Les fonctions étant sans état, l'environnement d'exécution est souvent initialisé à partir de zéro (lors d'un démarrage à froid). En cas de démarrage à froid, le contexte global de la fonction est évalué.
Si vos fonctions importent des modules, le temps de chargement de ces modules peut augmenter la latence d'appel lors d'un démarrage à froid. Pour réduire cette latence, ainsi que le temps nécessaire pour déployer votre fonction, chargez correctement les dépendances et ne chargez pas celles que votre fonction n'utilise pas.
Utiliser des variables globales pour réutiliser des objets lors de futurs appels
Il n'est pas garanti que l'état d'une fonction de Cloud Run Functions soit préservé pour les futurs appels. Cloud Run Functions recycle néanmoins souvent l'environnement d'exécution d'un appel précédent. Si vous déclarez une variable dans le champ d'application global, sa valeur peut être réutilisée dans les appels suivants sans avoir à être recalculée.
De cette façon, vous pouvez mettre en cache des objets qui peuvent être coûteux à recréer à chaque appel de fonction. Le déplacement de ces objets du corps de la fonction vers le champ d'application global peut entraîner des améliorations significatives des performances. Dans l'exemple suivant, un objet lourd est créé une seule fois par instance de fonction et partagé à travers tous les appels de fonction atteignant l'instance donnée :
Node.js
Python
Go
Java
C#
Ruby
PHP
Il est particulièrement important de mettre en cache les connexions réseau, les références de bibliothèque et les objets client API dans un champ d'application global. Consultez les exemples de la section Optimisation des réseaux.
Procéder à l'initialisation différée des variables globales
Si vous initialisez des variables dans un champ d'application global, le code d'initialisation est toujours exécuté via un appel de démarrage à froid, ce qui augmente la latence de votre fonction.
Dans certains cas, cela entraîne des délais d'inactivité intermittents pour les services qui sont appelés s'ils ne sont pas gérés correctement dans un bloc try
/catch
. Si certains objets ne sont pas utilisés dans tous les chemins de code, envisagez de procéder à une initialisation différée à la demande :
Node.js
Python
Go
Java
C#
Ruby
PHP
Les fonctions PHP ne peuvent pas conserver les variables entre les requêtes. L'exemple de champs d'application ci-dessus utilise le chargement différé pour mettre en cache les valeurs des variables globales dans un fichier.
Cette recommandation est d'autant plus importante si vous définissez plusieurs fonctions dans un seul fichier et que chaque fonction utilise des variables différentes. Si vous n'utilisez pas l'initialisation paresseuse, vous risquez de gaspiller des ressources sur des variables initialisées mais jamais utilisées.
Réduisez les démarrages à froid en définissant un nombre minimal d'instances
Par défaut, Cloud Run Functions adapte le nombre d'instances en fonction du nombre de requêtes entrantes. Vous pouvez modifier ce comportement par défaut en définissant un nombre minimal d'instances que Cloud Run Functions doit garder prêtes à diffuser les requêtes. La définition d'un nombre minimal d'instances réduit les démarrages à froid de votre application. Nous vous recommandons de définir un nombre minimal d'instances si votre application est sensible à la latence.
Pour savoir comment définir un nombre minimal d'instances, consultez la section Utiliser un nombre minimal d'instances.
Autres ressources
Pour en savoir plus sur l'optimisation des performances, regardez la vidéo "Google Cloud Performance Atlas" Temps de démarrage à froid de Cloud Run Functions.