Environnement d'exécution Cloud Functions

Cloud Functions s'exécute dans un environnement sans serveur entièrement géré, dans lequel Google s'occupe de l'infrastructure, des systèmes d'exploitation et des environnements d'exécution à votre place. Chaque fonction Cloud Functions s'exécute dans son propre contexte sécurisé et isolé, évolue automatiquement et dispose d'un cycle de vie indépendant des autres fonctions.

Environnements d'exécution

Cloud Functions accepte plusieurs environnements d'exécution de langage :

Exécution Image de base
Node.js 6 (obsolète) Debian 8
Node.js 8 (obsolète) Ubuntu 18.04
Node.js 10 Ubuntu 18.04
Node.js 12 Ubuntu 18.04
Python 3.7 Ubuntu 18.04
Python 3.8 Ubuntu 18.04
Go 1.11 Ubuntu 18.04
Go 1.13 Ubuntu 18.04
Java 11 Ubuntu 18.04
.NET Core 3.1 Ubuntu 18.04

Les mises à jour des environnements d'exécution sont généralement effectuées automatiquement, sauf indication contraire. Tous les environnements d'exécution reçoivent des mises à jour automatiques de la version du langage dès lors qu'elles sont mises à la disposition de la communauté des programmeurs. De même, Cloud Functions peut appliquer des mises à jour à d'autres aspects de l'environnement d'exécution, tels que le système d'exploitation ou les packages inclus. Ces mises à jour assurent la sécurité de votre fonction.

Fonctions sans état

Cloud Functions met en œuvre le paradigme sans serveur, dans lequel vous exécutez simplement votre code sans vous soucier de l'infrastructure sous-jacente, telle que les serveurs ou les machines virtuelles. Pour permettre à Google de gérer et de mettre à l'échelle automatiquement les fonctions, celles-ci doivent être sans état : un appel de fonction ne doit pas dépendre de l'état en mémoire défini par un appel précédent. Cependant, un état existant peut souvent être réutilisé à des fins d'optimisation des performances. Pour plus de détails, consultez les recommandations disponibles dans Conseils et astuces.

Par exemple, la valeur indiquée par le compteur et affichée par la fonction suivante ne correspond pas au nombre total d’appels de fonctions. En effet, ceux-ci peuvent être gérés par des instances de fonction différentes qui ne partagent pas de variables globales, de mémoire, de systèmes de fichiers ou d'autres états :

Node.js

// Global variable, but only shared within function instance.
let count = 0;

/**
 * HTTP Cloud Function that counts how many times
 * it is executed within a specific instance.
 *
 * @param {Object} req Cloud Function request context.
 * @param {Object} res Cloud Function response context.
 */
exports.executionCount = (req, res) => {
  count++;

  // Note: the total function invocation count across
  // all instances may not be equal to this value!
  res.send(`Instance execution count: ${count}`);
};

Python

# Global variable, modified within the function by using the global keyword.
count = 0

def statelessness(request):
    """
    HTTP Cloud Function that counts how many times it is executed
    within a specific instance.
    Args:
        request (flask.Request): The request object.
        <http://flask.pocoo.org/docs/1.0/api/#flask.Request>
    Returns:
        The response text, or any set of values that can be turned into a
        Response object using `make_response`
        <http://flask.pocoo.org/docs/1.0/api/#flask.Flask.make_response>.
    """
    global count
    count += 1

    # Note: the total function invocation count across
    # all instances may not be equal to this value!
    return 'Instance execution count: {}'.format(count)

Go


// Package http provides a set of HTTP Cloud Functions samples.
package http

import (
	"fmt"
	"net/http"
)

// count is a global variable, but only shared within a function instance.
var count = 0

// ExecutionCount is an HTTP Cloud Function that counts how many times it
// is executed within a specific instance.
func ExecutionCount(w http.ResponseWriter, r *http.Request) {
	count++

	// Note: the total function invocation count across
	// all instances may not be equal to this value!
	fmt.Fprintf(w, "Instance execution count: %d", count)
}

Java


import com.google.cloud.functions.HttpFunction;
import com.google.cloud.functions.HttpRequest;
import com.google.cloud.functions.HttpResponse;
import java.io.BufferedWriter;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicInteger;

public class ExecutionCount implements HttpFunction {

  private final AtomicInteger count = new AtomicInteger(0);

  @Override
  public void service(HttpRequest request, HttpResponse response)
      throws IOException {
    count.getAndIncrement();

    // Note: the total function invocation count across
    // all instances may not be equal to this value!
    BufferedWriter writer = response.getWriter();
    writer.write("Instance execution count: " + count);
  }
}

C#

using Google.Cloud.Functions.Framework;
using Microsoft.AspNetCore.Http;
using System.Threading;
using System.Threading.Tasks;

namespace ExecutionCount
{
    public class Function : IHttpFunction
    {
        // Note that this variable must be static, because a new instance is
        // created for each request. An alternative approach would be to use
        // dependency injection with a singleton resource injected into the function
        // constructor.
        private static int _count;

        public async Task HandleAsync(HttpContext context)
        {
            // Note: the total function invocation count across
            // all servers may not be equal to this value!
            int currentCount = Interlocked.Increment(ref _count);
            await context.Response.WriteAsync($"Server execution count: {currentCount}");
        }
    }
}

Si vous avez besoin de partager un état sur l'ensemble des appels de fonctions, votre fonction doit utiliser un service tel que Datastore, Firestore ou Cloud Storage pour conserver ces données. Pour obtenir la liste complète des options de stockage disponibles, consultez la page Choisir une option de stockage.

Autoscaling et simultanéité

Cloud Functions gère les requêtes entrantes en les attribuant à des instances de votre fonction. En fonction du volume de requêtes et du nombre d'instances de fonction existantes, Cloud Functions peut attribuer une requête à une instance existante ou en créer une.

Chaque instance d'une fonction ne gère qu'une seule requête simultanée à la fois. Cela signifie que lorsque votre code traite une requête, il est impossible qu'une deuxième requête soit acheminée vers la même instance. Ainsi, la requête d'origine peut utiliser la totalité des ressources (processeur et mémoire) que vous avez demandées.

Lorsque le volume de requêtes entrantes dépasse le nombre d'instances existantes, Cloud Functions peut démarrer plusieurs nouvelles instances pour gérer les requêtes. Ce comportement de scaling automatique permet à Cloud Functions de gérer de nombreuses requêtes en parallèle, chacune utilisant une instance différente de votre fonction.

Dans la mesure où les requêtes simultanées sont traitées par différentes instances de fonctions, elles ne partagent pas les mêmes variables ni la même mémoire locale. Ce dernier point sera abordé en détail plus loin dans ce document.

Contrôler le comportement de l'autoscaling

Cloud Functions vous permet de définir une limite sur le nombre total d'instances de fonction pouvant coexister à un moment donné. Dans certains cas, un scaling illimité n'est pas souhaitable. Par exemple, votre fonction peut dépendre d'une ressource (telle qu'une base de données) qui ne peut pas évoluer à la hausse au même degré que Cloud Functions. Une augmentation importante du volume de requêtes peut entraîner la création par Cloud Functions d'un nombre d'instances de fonction que votre base de données ne peut pas tolérer.

Démarrages à froid

Une nouvelle instance de fonction est créée dans deux cas :

  • Lorsque vous déployez une fonction.

  • Lorsqu'une nouvelle instance de fonction est automatiquement créée pour s'adapter à la charge actuelle ou, plus rarement, pour remplacer une instance existante.

Le lancement d'une nouvelle instance de fonction implique le chargement de l'environnement d'exécution et de votre code. Les requêtes qui impliquent le démarrage d'une instance de fonction (démarrage à froid) peuvent être plus lentes que les requêtes transmises à des instances de fonction existantes. Si votre fonction reçoit une charge constante, le nombre de démarrages à froid est généralement négligeable, à moins que votre fonction connaisse de nombreux plantages et nécessite un redémarrage de tout son environnement. Consultez la section Erreurs pour savoir comment correctement gérer les erreurs et éviter les démarrages à froid.

Durée de vie de l'instance de fonction

L'environnement exécutant une instance de fonction est généralement résilient et est réutilisé pour les appels de fonctions ultérieurs, à moins que le nombre d'instances soit réduit (en raison du manque de trafic en cours) ou que votre fonction se bloque. Cela signifie que lorsque l'exécution d'une fonction se termine, un autre appel de fonction peut être géré par cette même instance de fonction. Par conséquent, il est recommandé de définir l'état du cache pour tous les appels sur champ d'application global dans la mesure du possible. Votre fonction doit toujours être prête à fonctionner sans ce cache disponible, car rien ne garantit que l'appel suivant sera transmis à la même instance de fonction (voir Fonctions sans état).

Champ d'application de la fonction et champ d'application global

Un appel de fonction unique entraîne seulement l'exécution du corps de la fonction déclarée comme point d'entrée. Le champ d'application global du fichier de fonction, qui doit contenir la définition de la fonction, est exécuté à chaque démarrage à froid, sauf si l'instance a déjà été initialisée.

Node.js

// Global (instance-wide) scope
// This computation runs at instance cold-start
const instanceVar = heavyComputation();

/**
 * HTTP function that declares a variable.
 *
 * @param {Object} req request context.
 * @param {Object} res response context.
 */
exports.scopeDemo = (req, res) => {
  // Per-function scope
  // This computation runs every time this function is called
  const functionVar = lightComputation();

  res.send(`Per instance: ${instanceVar}, per function: ${functionVar}`);
};

Python

# Global (instance-wide) scope
# This computation runs at instance cold-start
instance_var = heavy_computation()

def scope_demo(request):
    """
    HTTP Cloud Function that declares a variable.
    Args:
        request (flask.Request): The request object.
        <http://flask.pocoo.org/docs/1.0/api/#flask.Request>
    Returns:
        The response text, or any set of values that can be turned into a
        Response object using `make_response`
        <http://flask.pocoo.org/docs/1.0/api/#flask.Flask.make_response>.
    """

    # Per-function scope
    # This computation runs every time this function is called
    function_var = light_computation()
    return 'Instance: {}; function: {}'.format(instance_var, function_var)

Go


// h is in the global (instance-wide) scope.
var h string

// init runs during package initialization. So, this will only run during an
// an instance's cold start.
func init() {
	h = heavyComputation()
}

// ScopeDemo is an example of using globally and locally
// scoped variables in a function.
func ScopeDemo(w http.ResponseWriter, r *http.Request) {
	l := lightComputation()
	fmt.Fprintf(w, "Global: %q, Local: %q", h, l)
}

Java


import com.google.cloud.functions.HttpFunction;
import com.google.cloud.functions.HttpRequest;
import com.google.cloud.functions.HttpResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;

public class Scopes implements HttpFunction {
  // Global (instance-wide) scope
  // This computation runs at instance cold-start.
  // Warning: Class variables used in functions code must be thread-safe.
  private static final int INSTANCE_VAR = heavyComputation();

  @Override
  public void service(HttpRequest request, HttpResponse response)
      throws IOException {
    // Per-function scope
    // This computation runs every time this function is called
    int functionVar = lightComputation();

    var writer = new PrintWriter(response.getWriter());
    writer.printf("Instance: %s; function: %s", INSTANCE_VAR, functionVar);
  }

  private static int lightComputation() {
    int[] numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    return Arrays.stream(numbers).sum();
  }

  private static int heavyComputation() {
    int[] numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    return Arrays.stream(numbers).reduce((t, x) -> t * x).getAsInt();
  }
}

Le champ d'application de votre fonction aura été exécuté une fois avant que son code soit appelé dans une nouvelle instance de fonction (et pour chaque création ultérieure d'une autre instance de fonction). Toutefois, vous ne devez pas dépendre du nombre total d’exécutions de champ d'application global, ni sur le délai entre chacune d'elles, car ces facteurs sont soumis à l'autoscaling automatique géré par Google.

Chronologie d'exécution des fonctions

Une fonction a accès aux ressources demandées (processeur et mémoire) uniquement pendant sa durée d'exécution. L'exécution du code en dehors de la période d'exécution n'est pas garantie et peut être interrompue à tout moment. Par conséquent, vous devez toujours signaler la fin de l'exécution de votre fonction et éviter d'exécuter du code au-delà. Pour en savoir plus, consultez les pages Fonctions HTTP et Fonctions d'arrière-plan.

Par exemple, le code exécuté après l'envoi de la réponse HTTP peut être interrompu à tout moment :

Node.js

/**
 * HTTP Cloud Function that may not completely
 * execute due to early HTTP response
 *
 * @param {Object} req Cloud Function request context.
 * @param {Object} res Cloud Function response context.
 */
exports.afterResponse = (req, res) => {
  res.end();

  // This statement may not execute
  console.log('Function complete!');
};

Il est important de prendre en compte la chronologie d'exécution lors de l'initialisation de votre application. Les tâches en arrière-plan ne doivent pas être créées dans le champ d'application global lors de l'initialisation, car elles s'exécutent en dehors de la durée d'une requête.

Garanties d'exécution

Vos fonctions sont généralement appelées une seule fois pour chaque événement entrant. Cependant, Cloud Functions ne garantit pas un appel unique dans tous les cas, en raison de différences dans les scénarios d'erreur.

Le nombre maximum ou minimum d'appels de fonctions pour un seul événement dépend du type de fonction :

  • Les fonctions HTTP sont appelées au maximum une fois. Cela est dû à la nature synchrone des appels HTTP. Ainsi, toute erreur survenant lors de l'appel de la fonction sera affichée sans nouvelle tentative. L'appelant d'une fonction HTTP doit assumer la gestion des erreurs, ainsi que des nouvelles tentatives, le cas échéant.

  • Les fonctions d'arrière-plan sont appelées au minimum une fois. Cela est dû à la nature asynchrone de la gestion de ces événements, dans lesquels aucun appelant n'attend de réponse. Dans de rares cas, le système peut appeler une fonction d'arrière-plan plusieurs fois afin d'assurer la diffusion de l'événement. Si un appel de fonction d'arrière-plan échoue avec une erreur, elle ne sera appelée à nouveau que si de nouvelles tentatives en cas d'échec sont activées pour cette fonction.

Pour vous assurer que votre fonction se comporte correctement lors de nouvelles tentatives d’exécution, vous devez la rendre idempotente en la mettant en œuvre de sorte qu'un événement produise les résultats souhaités (et les effets secondaires), même s’il est transmis plusieurs fois. Dans le cas des fonctions HTTP, cela signifie également renvoyer la valeur souhaitée, même si l'appelant réessaie d'appeler le point de terminaison de la fonction HTTP. Consultez la page Répétition des tentatives des fonctions d'arrière-plan pour en savoir plus sur la manière de rendre votre fonction idempotente.

Erreurs

La méthode recommandée pour qu'une fonction signale une erreur dépend du type de fonction :

  • Les fonctions HTTP doivent afficher les codes d'état HTTP appropriés indiquant une erreur. Voir Fonctions HTTP pour obtenir des exemples.

  • Les fonctions d'arrière-plan doivent enregistrer et afficher un message d'erreur. Consultez la page Fonctions d'arrière-plan pour obtenir des exemples.

Si une erreur est affichée de manière appropriée, l'instance de fonction qui a affiché l'erreur est étiquetée comme se comportant normalement et peut servir, le cas échéant, à de futures requêtes.

Si votre code ou tout autre code que vous appelez envoie une exception non détectée ou bloque le processus en cours, l'instance de fonction peut être redémarrée avant de traiter l'appel suivant. Cela peut conduire à plus de démarrages à froid et augmenter la latence. Cette approche est donc déconseillée.

Reportez-vous à la section Signaler des erreurs pour plus d'informations sur la manière de signaler des erreurs dans Cloud Functions.

Délai avant expiration

La durée d'exécution d'une fonction est limitée par le délai avant expiration, que vous pouvez spécifier au moment du déploiement de la fonction. Par défaut, une fonction expire après 1 minute, mais vous pouvez prolonger cette période jusqu'à 9 minutes.

Lorsque l'exécution de la fonction dépasse ce délai, un état d'erreur est immédiatement renvoyé à l'appelant. Les ressources du processeur utilisées par l'instance de la fonction dont le délai a expiré sont limitées, et le traitement des requêtes peut être immédiatement mis en veille. Les tâches mises en veille peuvent ou non être traitées lors de requêtes ultérieures, ce qui peut avoir des effets secondaires inattendus.

L'extrait de code ci-dessous inclut des lignes de code prévues pour s'exécuter 2 minutes après le démarrage de l'exécution de la fonction. Si le délai avant expiration est défini comme étant de 1 minute, ce code peut ne jamais s'exécuter :

Node.js

/**
 * HTTP Cloud Function that may not completely
 * execute due to function execution timeout
 *
 * @param {Object} req Cloud Function request context.
 * @param {Object} res Cloud Function response context.
 */
exports.afterTimeout = (req, res) => {
  setTimeout(() => {
    // May not execute if function's timeout is <2 minutes
    console.log('Function running...');
    res.end();
  }, 120000); // 2 minute delay
};

Python

def timeout(request):
    print('Function running...')
    time.sleep(120)

    # May not execute if function's timeout is <2 minutes
    print('Function completed!')
    return 'Function completed!'

Go


// Package tips contains tips for writing Cloud Functions in Go.
package tips

import (
	"fmt"
	"log"
	"net/http"
	"time"
)

// Timeout sleeps for 2 minutes and may time out before finishing.
func Timeout(w http.ResponseWriter, r *http.Request) {
	log.Println("Function execution started...")
	time.Sleep(2 * time.Minute)
	log.Println("Function completed!")
	fmt.Fprintln(w, "Function completed!")
}

Java


package functions;

import com.google.cloud.functions.HttpFunction;
import com.google.cloud.functions.HttpRequest;
import com.google.cloud.functions.HttpResponse;
import java.io.BufferedWriter;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;

public class AfterTimeout implements HttpFunction {
  private static final Logger logger = Logger.getLogger(AfterTimeout.class.getName());

  // Simple function to return "Hello World"
  @Override
  public void service(HttpRequest request, HttpResponse response)
      throws IOException, InterruptedException {
    logger.info("Function running...");
    TimeUnit.MINUTES.sleep(2);

    // May not execute if function's timeout is <2 minutes
    logger.info("Function completed!");
    BufferedWriter writer = response.getWriter();
    writer.write("Function completed!");
  }
}

Dans certains cas, le code ci-dessus peut s'exécuter correctement, mais de manière inattendue. Considérons l'éventualité où la fonction expire. L'instance qui traite la requête est mise en veille (en limitant le processeur). Les tâches en attente sont mises en veille. Si une requête ultérieure est acheminée vers la même instance, les tâches reprennent et Function running... est émis dans les journaux.

L'un des symptômes courants de ce comportement est que les tâches et les journaux d'une requête donnent l'impression d'être transmis à une requête ultérieure. Évitez de dépendre de ce comportement, car vous ne pouvez pas compter sur la reprise des tâches qui ont été mises en veille. Votre fonction devrait plutôt éviter les dépassements de délai avant expiration en combinant les techniques suivantes :

  1. Définissez un délai avant expiration supérieur au temps d'exécution attendu de la fonction.
  2. Effectuez le suivi du temps restant pendant l'exécution, et effectuez une sortie ou un nettoyage anticipé.

Pour définir la durée d'exécution maximale d'une fonction à l'aide de l'outil de ligne de commande gcloud, utilisez l'option --timeout au moment du déploiement :

gcloud functions deploy FUNCTION_NAME --timeout=TIMEOUT FLAGS...

Dans la commande ci-dessus, FLAGS... fait référence aux autres options que vous transmettez lors du déploiement de votre fonction. Pour en savoir plus sur la commande deploy, reportez-vous à la documentation de référence sur gcloud functions deploy.

Vous pouvez également définir le délai avant expiration lors de la création de la fonction dans Cloud Console, comme suit :

  1. Accédez à la page de présentation de Cloud Functions dans Cloud Console.

  2. Cliquez sur Create function.

  3. Renseignez les champs obligatoires de votre fonction.

  4. Cliquez sur Plus pour afficher les paramètres avancés.

  5. Saisissez une valeur dans le champ Délai avant expiration.

Système de fichiers

L'environnement d'exécution de fonction contient un fichier de fonction exécutable, ainsi que des fichiers et des répertoires inclus dans le package de fonctions déployées, comme les dépendances locales. Ces fichiers sont disponibles dans un répertoire en lecture seule, déterminé en fonction de l'emplacement du fichier de fonction. Notez que le répertoire de la fonction peut être différent du répertoire de travail actuel.

L'exemple suivant répertorie les fichiers situés dans le répertoire de la fonction :

Node.js

const fs = require('fs');

/**
 * HTTP Cloud Function that lists files in the function directory
 *
 * @param {Object} req Cloud Function request context.
 * @param {Object} res Cloud Function response context.
 */
exports.listFiles = (req, res) => {
  fs.readdir(__dirname, (err, files) => {
    if (err) {
      console.error(err);
      res.sendStatus(500);
    } else {
      console.log('Files', files);
      res.sendStatus(200);
    }
  });
};

Python

def list_files(request):
    import os
    from os import path

    root = path.dirname(path.abspath(__file__))
    children = os.listdir(root)
    files = [c for c in children if path.isfile(path.join(root, c))]
    return 'Files: {}'.format(files)

Go


// Package tips contains tips for writing Cloud Functions in Go.
package tips

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
)

// ListFiles lists the files in the current directory.
// Uses directory "serverless_function_source_code" as defined in the Go
// Functions Framework Buildpack.
// See https://github.com/GoogleCloudPlatform/buildpacks/blob/56eaad4dfe6c7bd0ecc4a175de030d2cfab9ae1c/cmd/go/functions_framework/main.go#L38.
func ListFiles(w http.ResponseWriter, r *http.Request) {
	files, err := ioutil.ReadDir("./serverless_function_source_code")
	if err != nil {
		http.Error(w, "Unable to read files", http.StatusInternalServerError)
		log.Printf("ioutil.ListFiles: %v", err)
		return
	}
	fmt.Fprintln(w, "Files:")
	for _, f := range files {
		fmt.Fprintf(w, "\t%v\n", f.Name())
	}
}

Java


import com.google.cloud.functions.HttpFunction;
import com.google.cloud.functions.HttpRequest;
import com.google.cloud.functions.HttpResponse;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;

public class FileSystem implements HttpFunction {

  // Lists the files in the current directory.
  @Override
  public void service(HttpRequest request, HttpResponse response)
      throws IOException {
    File currentDirectory = new File(".");
    File[] files = currentDirectory.listFiles();
    PrintWriter writer = new PrintWriter(response.getWriter());
    writer.println("Files:");
    for (File f : files) {
      writer.printf("\t%s%n", f.getName());
    }
  }
}

C#

using Google.Cloud.Functions.Framework;
using Microsoft.AspNetCore.Http;
using System.IO;
using System.Threading.Tasks;

namespace FileSystem
{
    public class Function : IHttpFunction
    {
        public async Task HandleAsync(HttpContext context)
        {
            string[] files = Directory.GetFiles(".");

            await context.Response.WriteAsync("Files:\n");
            foreach (string file in files)
            {
                await context.Response.WriteAsync($"\t{file}\n");
            }
        }
    }
}

Vous pouvez également charger du code à partir d'autres fichiers déployés avec la fonction.

La seule partie accessible en écriture du système de fichiers est le répertoire /tmp que vous pouvez utiliser pour stocker des fichiers temporaires dans une instance de fonction. Il s'agit d'un point de montage du disque local, appelé volume "tmpfs", dans lequel les données écrites sur le volume sont stockées en mémoire. Notez qu'il consommera des ressources mémoire provisionnées pour la fonction.

Le reste du système de fichiers est en lecture seule, et est accessible par la fonction.

Réseau

Votre fonction peut accéder à l'Internet public en utilisant des bibliothèques standards proposées par l'environnement d'exécution ou des fournisseurs tiers. Par exemple, vous pouvez appeler un point de terminaison HTTP, comme indiqué ci-dessous :

Node.js

const fetch = require('node-fetch');

/**
 * HTTP Cloud Function that makes an HTTP request
 *
 * @param {Object} req Cloud Function request context.
 * @param {Object} res Cloud Function response context.
 */
exports.makeRequest = async (req, res) => {
  const url = 'https://example.com'; // URL to send the request to
  const externalRes = await fetch(url);
  res.sendStatus(externalRes.ok ? 200 : 500);
};

Python

def make_request(request):
    """
    HTTP Cloud Function that makes another HTTP request.
    Args:
        request (flask.Request): The request object.
        <http://flask.pocoo.org/docs/1.0/api/#flask.Request>
    Returns:
        The response text, or any set of values that can be turned into a
        Response object using `make_response`
        <http://flask.pocoo.org/docs/1.0/api/#flask.Flask.make_response>.
    """
    import requests

    # The URL to send the request to
    url = 'http://example.com'

    # Process the request
    response = requests.get(url)
    response.raise_for_status()
    return 'Success!'

Go


// Package http provides a set of HTTP Cloud Functions samples.
package http

import (
	"fmt"
	"net/http"
	"time"
)

var urlString = "https://example.com"

// client is used to make HTTP requests with a 10 second timeout.
// http.Clients should be reused instead of created as needed.
var client = &http.Client{
	Timeout: 10 * time.Second,
}

// MakeRequest is an example of making an HTTP request. MakeRequest uses a
// single http.Client for all requests to take advantage of connection
// pooling and caching. See https://godoc.org/net/http#Client.
func MakeRequest(w http.ResponseWriter, r *http.Request) {
	resp, err := client.Get(urlString)
	if err != nil {
		http.Error(w, "Error making request", http.StatusInternalServerError)
		return
	}
	if resp.StatusCode != http.StatusOK {
		msg := fmt.Sprintf("Bad StatusCode: %d", resp.StatusCode)
		http.Error(w, msg, http.StatusInternalServerError)
		return
	}
	fmt.Fprintf(w, "ok")
}

Java


import com.google.cloud.functions.HttpFunction;
import com.google.cloud.functions.HttpRequest;
import com.google.cloud.functions.HttpResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpResponse.BodyHandlers;
import java.time.Duration;

public class SendHttpRequest implements HttpFunction {

  // Create a client with some reasonable defaults. This client can be reused for multiple requests.
  // (java.net.httpClient also pools connections automatically by default.)
  private static HttpClient client =
      HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(10)).build();

  @Override
  public void service(HttpRequest request, HttpResponse response)
      throws IOException, InterruptedException {
    // Create a GET sendHttpRequest to "http://example.com"
    String url = "http://example.com";
    var getRequest = java.net.http.HttpRequest.newBuilder().uri(URI.create(url)).GET().build();

    // Send the sendHttpRequest using the client
    var getResponse = client.send(getRequest, BodyHandlers.ofString());

    // Write the results to the output:
    var writer = new PrintWriter(response.getWriter());
    writer.printf("Received code '%s' from url '%s'.", getResponse.statusCode(), url);
  }
}

C#

using Google.Cloud.Functions.Framework;
using Google.Cloud.Functions.Hosting;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using System.Net.Http;
using System.Threading.Tasks;

namespace SendHttpRequest
{
    // Dependency injection configuration, executed during server startup.
    public class Startup : FunctionsStartup
    {
        public override void ConfigureServices(WebHostBuilderContext context, IServiceCollection services)
        {
            // Make an HttpClient available to our function via dependency injection.
            // There are many options here; see
            // https://docs.microsoft.com/en-us/aspnet/core/fundamentals/http-requests
            // for more details.
            services.AddHttpClient<IHttpFunction, Function>();
        }
    }

    // Function, decorated with the FunctionsStartup attribute to specify the startup class
    // for dependency injection.
    [FunctionsStartup(typeof(Startup))]
    public class Function : IHttpFunction
    {
        private readonly HttpClient _httpClient;

        public Function(HttpClient httpClient) =>
            _httpClient = httpClient;

        public async Task HandleAsync(HttpContext context)
        {
            string url = "http://example.com";
            using (HttpResponseMessage clientResponse = await _httpClient.GetAsync(url))
            {
                await context.Response.WriteAsync($"Received code '{(int) clientResponse.StatusCode}' from URL '{url}'.");
            }
        }
    }
}

Essayez de réutiliser les connexions réseau pour vos appels de fonctions, comme décrit dans la section Optimisation des réseaux. Notez toutefois qu'une connexion inutilisée pendant 2 minutes peut être fermée par le système et que toute nouvelle tentative d'utilisation d'une connexion fermée entraîne une erreur de type "Connexion réinitialisée". Votre code doit utiliser une bibliothèque qui gère les connexions fermées de manière appropriée, ou bien les gérer explicitement si vous utilisez des constructions réseau de bas niveau.

Fonctions multiples

Chaque fonction déployée est isolée de toutes les autres fonctions, même celles déployées à partir du même fichier source. Plus précisément, elles ne partagent pas de mémoire, de variables globales, de systèmes de fichiers ou d'autres états.

Pour partager des données entre des fonctions déployées, vous pouvez utiliser des services de stockage tels que Datastore, Firestore ou Cloud Storage. Vous pouvez également appeler une fonction à partir d'une autre, à l'aide des déclencheurs appropriés. Par exemple, envoyez une requête HTTP au point de terminaison d'une fonction HTTP ou publiez un message dans un sujet Pub/Sub pour déclencher une fonction Pub/Sub.