Cloud Functions-Ausführungsumgebung

Cloud Functions-Funktionen werden in einer vollständig verwalteten, serverlosen Umgebung ausgeführt, in der Google sich um die Verwaltung der Infrastruktur, Betriebssysteme und Laufzeitumgebungen kümmert. Jede Cloud Functions-Funktion wird in ihrem eigenen isolierten, sicheren Ausführungskontext bereitgestellt und automatisch skaliert. Ihr Lebenszyklus ist von dem anderer Funktionen unabhängig.

Laufzeiten

Cloud Functions unterstützt mehrere Sprachlaufzeiten. Sie benötigen den Laufzeit-ID-Wert, wenn Sie Funktionen über die Befehlszeile oder über Terraform bereitstellen.

Laufzeit Basis-Image Laufzeit-ID
Node.js 6 (außer Betrieb genommen) Debian 8 nodejs6
Node.js 8 (verworfen) Ubuntu 18.04 nodejs8
Node.js 10 Ubuntu 18.04 nodejs10
Node.js 12 Ubuntu 18.04 nodejs12
Node.js 14 Ubuntu 18.04 nodejs14
Python 3.7 Ubuntu 18.04 python37
Python 3.8 Ubuntu 18.04 python38
Go 1.11 (verworfen) Ubuntu 18.04 go111
Go 1.13 Ubuntu 18.04 go113
Java 11 Ubuntu 18.04 java11
.NET Core 3.1 Ubuntu 18.04 dotnet3
Ruby 2.6 Ubuntu 18.04 ruby26
Ruby 2.7 Ubuntu 18.04 ruby27

Aktualisierungen der Laufzeiten erfolgen automatisch, sofern nicht anders angegeben. Alle Laufzeiten werden automatisch an die Sprachversion angepasst, sobald sie der Sprachcommunity zur Verfügung gestellt werden. In gleicher Weise kann Cloud Functions Aktualisierungen auf andere Aspekte der Ausführungsumgebung anwenden, z. B. das Betriebssystem oder eingeschlossene Pakete. Diese Aktualisierungen tragen zur Sicherheit Ihrer Funktion bei.

Zustandslose Funktionen

Cloud Functions sind serverlos. Sie müssen sich bei der Codeausführung also nicht um die darunterliegende Infrastruktur wie Server oder virtuelle Maschinen kümmern. Damit Google die Funktionen automatisch verwalten und skalieren kann, müssen sie zustandslos sein. Ein Funktionsaufruf sollte nicht auf dem Speicherzustand basieren, der durch einen vorherigen Aufruf festgelegt wurde. Oft kann ein vorhandener Zustand jedoch wiederverwendet werden, um die Leistung zu steigern. Weitere Informationen finden Sie in den Tipps und Tricks.

Beispielsweise entspricht der von der folgenden Funktion zurückgegebene Zählerwert nicht der Gesamtzahl der Funktionsaufrufe, da Aufrufe von verschiedenen Funktionsinstanzen verarbeitet werden können, die nicht die gleichen globalen Variablen, Speicher, Dateisysteme oder andere Zustände haben:

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}");
        }
    }
}

Ruby

require "functions_framework"

# Global variable, but scoped only within one function instance.
$count = 0

FunctionsFramework.http "execution_count" do |_request|
  $count += 1

  # Note: the total function invocation count across all instances
  # may not be equal to this value!
  "Instance execution count: #{$count}"
end

Wenn Sie den Status für Funktionsaufrufe freigeben müssen, sollte die Funktion einen Dienst wie Datenspeicher, Firestore oder Cloud Storage verwenden, um Daten zu speichern. Eine vollständige Liste der verfügbaren Speicheroptionen finden Sie unter Speicheroption auswählen.

Automatische Skalierung und Gleichzeitigkeit

Cloud Functions verarbeitet eingehende Anfragen, indem diese den Instanzen Ihrer Funktion zugewiesen werden. Abhängig von der Anzahl der Anfragen sowie der Anzahl der vorhandenen Funktionsinstanzen kann Cloud Functions eine Anfrage einer vorhandenen Instanz zuweisen oder eine neue erstellen.

Jede Instanz einer Funktion verarbeitet jeweils nur eine einzige Anfrage. Das bedeutet, dass keine zweite Anfrage an dieselbe Instanz weitergeleitet werden kann, während Ihr Code eine Anfrage verarbeitet. Die ursprüngliche Anfrage kann also die gesamte von Ihnen angeforderte Menge an Ressourcen (CPU und Arbeitsspeicher) nutzen.

Wenn das Volumen der eingehenden Anfragen die Anzahl der vorhandenen Instanzen überschreitet, kann Cloud Functions mehrere neue Instanzen zur Verarbeitung von Anfragen starten. Dieses automatische Skalierungsverhalten ermöglicht es Cloud Functions, viele Anfragen parallel zu verarbeiten, wobei jede eine andere Instanz Ihrer Funktion verwendet.

Da gleichzeitige Anfragen von verschiedenen Funktionsinstanzen verarbeitet werden, teilen diese keine Variablen oder lokalen Arbeitsspeicher. Darauf wird später in diesem Dokument noch genauer eingegangen.

Autoscaling-Verhalten steuern

Mit Cloud Functions können Sie eine Grenze festlegen, wie viele Funktionsinstanzen gleichzeitig koexistieren können. In einigen Fällen ist eine unbegrenzte Skalierung nicht sinnvoll. Ihre Funktion kann z. B. von einer Ressource abhängen (wie einer Datenbank), die sich nicht im gleichen Maße wie Cloud Functions skalieren lässt. Ein starker Anstieg des Anforderungsvolumens kann dazu führen, dass Cloud Functions mehr Funktionsinstanzen erstellt, als Ihre Datenbank bewältigen kann.

Kaltstarts

Eine neue Funktionsinstanz wird in zwei Fällen gestartet:

  • Wenn Sie die Funktion bereitstellen

  • Wenn die Funktion als Reaktion auf eine gestiegene Arbeitslast oder als Ersatz für eine andere Instanz automatisch erstellt wird.

Beim Starten einer neuen Funktionsinstanz werden die Laufzeit und der Code geladen. Anfragen, die den Start einer Funktionsinstanz (Kaltstart) erfordern, benötigen möglicherweise mehr Zeit als solche, die von einer vorhandenen Funktionsinstanz verarbeitet werden können. Wenn Ihre Funktion eine konstante Arbeitslast verarbeitet, ist die Anzahl der Kaltstarts normalerweise vernachlässigbar, es sei denn, sie stürzt häufig ab und die Funktionsumgebung muss neu gestartet werden. Unter Fehler finden Sie weitere Informationen zur Fehlerbehandlung und dazu, wie sich Kaltstarts vermeiden lassen.

Lebensdauer einer Funktionsinstanz

Die Umgebung, in der eine Funktionsinstanz ausgeführt wird, ist in der Regel ausfallsicher und wird von nachfolgenden Funktionsaufrufen wiederverwendet, es sei denn, die Anzahl der Instanzen wird verkleinert (aufgrund geringer Zugriffszahlen) oder die Funktion stürzt ab. Das bedeutet, wenn eine Funktionsausführung endet, kann dieselbe Funktionsinstanz einen weiteren Funktionsaufruf verarbeiten. Deswegen ist es auch eine gute Idee, den Zustand für mehrere Aufrufe möglichst im globalen Geltungsbereich zwischenzuspeichern. Die Funktion sollte aber auch ohne den zwischengespeicherten Zustand ihre Aufgaben erfüllen können, da es keine Garantie dafür gibt, dass der nächste Aufruf bei derselben Funktionsinstanz landen wird (siehe Zustandslose Funktionen).

Funktionsbereich oder globaler Bereich

Beim Aufrufen einer einzelnen Funktion wird nur der als Einstiegspunkt deklarierte Funktionsteil ausgeführt. Der globale Gültigkeitsbereich in der Funktionsdatei, die in der Regel die Funktionsdefinition enthält, wird bei jedem Kaltstart ausgeführt, jedoch nicht, wenn die Instanz bereits initialisiert wurde.

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();
  }
}

Sie können davon ausgehen, dass der globale Geltungsbereich genau einmal ausgeführt wurde, bevor Ihr Funktionscode in einer neuen Funktionsinstanz (und bei jeder nachfolgenden Erstellung einer neuen Funktionsinstanz) aufgerufen wird. Eine Abhängigkeit von der Gesamtanzahl oder dem Zeitpunkt der Ausführungen im globalen Bereich ist jedoch zu vermeiden, da diese von der von Google verwalteten automatischen Skalierung abhängig sind.

Zeitlicher Ablauf der Funktionsausführung

Eine Funktion hat nur für die Dauer der Funktionsausführung Zugriff auf die angeforderten Ressourcen (CPU und Speicher). Code, der außerhalb des Ausführungszeitraums ausgeführt wird, wird nicht garantiert ausgeführt und kann jederzeit angehalten werden. Daher sollten Sie das Ende der Ausführung der Funktion immer korrekt signalisieren und vermeiden, dass Code darüber hinaus ausgeführt wird. Näheres dazu finden Sie unter HTTP-Funktionen und Hintergrundfunktionen.

Der nach dem Senden der HTTP-Antwort ausgeführte Code könnte zum Beispiel jederzeit unterbrochen werden:

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!');
};

Es ist wichtig, den zeitlichen Ablauf der Ausführung bei der Initialisierung Ihrer Anwendung zu berücksichtigen. Hintergrundaufgaben sollten während der Initialisierung nicht im globalen Bereich erstellt werden, da sie außerhalb der Dauer einer Anfrage ausgeführt werden.

Ausführungsgarantien

Eine Funktion wird normalerweise einmal für jedes eingehende Ereignis aufgerufen. Cloud Functions kann den einmaligen Aufruf aufgrund von Unterschieden in den Fehlerszenarien aber nicht in allen Fällen garantieren.

Die maximale oder minimale Häufigkeit, mit der eine Funktion für ein einzelnes Ereignis aufgerufen wird, hängt von ihrem Typ ab:

  • HTTP-Funktionen werden höchstens einmal aufgerufen. Das liegt daran, dass HTTP-Aufrufe synchron erfolgen. Jeder Fehler bei der Verarbeitung des Funktionsaufrufs wird ohne einen erneuten Versuch zurückgegeben. Es wird erwartet, dass der Aufrufer der HTTP-Funktion die Fehler behandelt und bei Bedarf den Aufruf wiederholt.

  • Hintergrundfunktionen werden mindestens einmal aufgerufen. Das liegt an der asynchronen Behandlung von Ereignissen, bei denen kein Aufrufer auf die Antwort wartet. In seltenen Fällen kann das System eine Hintergrundfunktion mehr als einmal aufrufen, um die Lieferung des Ereignisses sicherzustellen. Wenn ein Aufruf einer Hintergrundfunktion aufgrund eines Fehlers fehlschlägt, wird sie nur dann wieder aufgerufen, wenn für diese Funktion Wiederholungsversuche bei Fehlern aktiviert sind.

Damit sich die Funktion bei wiederholten Ausführungsversuchen korrekt verhält, sollten Sie sie idempotent machen, indem Sie sie so implementieren, dass ein Ereignis zu den gewünschten Ergebnissen (und Nebeneffekten) führt, auch wenn es mehrmals zurückgegeben wird. Für HTTP-Funktionen bedeutet das, dass der gewünschte Wert geliefert wird, selbst wenn der Aufrufer die Aufrufe an den HTTP-Funktionsendpunkt wiederholt. Weitere Informationen dazu, wie Sie Ihre Funktion idempotent machen, finden Sie unter Hintergrundfunktionen wiederholen.

Fehler

Die richtige Art der Fehlersignalisierung hängt vom Funktionstyp ab:

  • HTTP-Funktionen sollten HTTP-Statuscodes zurückgeben, die den Fehler anzeigen. Beispiele finden Sie unter HTTP-Funktionen.

  • Hintergrundfunktionen sollten den Fehler protokollieren und eine Fehlermeldung zurückgeben. Beispiele finden Sie unter Hintergrundfunktionen.

Wird ein Fehler auf die empfohlene Weise zurückgegeben, gilt die Funktionsinstanz, die den Fehler zurückgegeben hat, als normal und kann bei Bedarf zukünftige Anfragen verarbeiten.

Wenn Ihr Code oder jeder andere Code, den Sie aufrufen, eine unbehandelte Ausnahme auslöst oder den aktuellen Prozess zum Abstürzen bringt, kann die Funktionsinstanz neu gestartet werden, bevor der nächste Aufruf verarbeitet wird. Das kann zu einer erhöhten Anzahl von Kaltstarts und damit einer höheren Latenz führen, weshalb davon abgeraten wird.

Weitere Informationen zum Melden von Fehlern in Cloud Functions finden Sie unter Fehler melden.

Zeitlimit

Die Ausführungszeit der Funktion kann durch ein Zeitlimit begrenzt werden, das Sie beim Bereitstellen der Funktion angeben können. Eine Funktion läuft standardmäßig nach 1 Minute ab, Sie können diesen Zeitraum aber auf bis zu 9 Minuten verlängern.

Sobald die Ausführung der Funktion das Zeitlimit überschreitet, wird dem Aufrufer ein Fehlerstatus zurückgegeben. CPU-Ressourcen, die von der abgelaufenen Funktionsinstanz verwendet werden, werden gedrosselt und die Verarbeitung der Anfrage kann sofort pausiert werden. Pausierte Aufträge können bei nachfolgenden Anfragen fortgesetzt werden, was unerwartete Auswirkungen haben kann.

Das folgende Snippet enthält Code, der 2 Minuten nach dem Start der Funktionsausführung ausgeführt werden soll. Bei einem Zeitlimit von 1 Minute würde dieser Code möglicherweise niemals ausgeführt:

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!");
  }
}

Unter bestimmten Umständen kann der obige Code erfolgreich, aber in unerwarteter Weise ausgeführt werden. Stellen Sie sich vor, was passiert, wenn die Funktion das Zeitlimit überschreitet. Die Instanz, die die Anforderung liefert, wird pausiert (durch Drosselung der CPU). Ausstehende Arbeiten werden pausiert. Wenn eine nachfolgende Anfrage an dieselbe Instanz weitergeleitet wird, wird die Arbeit fortgesetzt und Function running... wird an Logs gesendet.

Als häufiges Symptom dieses Verhaltens scheint es dann so, dass Arbeit und Logs aus einer Anforderung in eine nachfolgende Anforderung "überlaufen". Da Sie nicht sicher davon ausgehen können, dass pausierte Arbeit fortgesetzt wird, sollten Sie sich nicht auf dieses Verhalten verlassen. Stattdessen sollte Ihre Funktion Zeitüberschreitungen durch eine Kombination der folgenden Methoden vermeiden:

  1. Legen Sie ein Zeitlimit fest, das über der erwarteten Ausführungszeit liegt.
  2. Verfolgen Sie die verbleibende Ausführungszeit und führen Sie die Bereinigung bzw. den Exit frühzeitig durch.

Nutzen Sie bei der Bereitstellung das Flag --timeout, um die maximale Ausführungszeit einer Funktion mit dem Befehlszeilentool gcloud festzulegen:

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

Im obigen Befehl bezieht sich FLAGS... auf andere Optionen, die Sie während der Bereitstellung Ihrer Funktion übergeben. Eine vollständige Referenz zum deploy-Befehl finden Sie unter gcloud functions deploy.

Sie können das Zeitlimit auch während der Funktionserstellung in der Cloud Console festlegen:

  1. Gehen Sie zur Cloud Functions-Übersichtsseite in der Cloud Console.

  2. Klicken Sie auf Funktion erstellen.

  3. Füllen Sie die erforderlichen Felder für die Funktion aus.

  4. Klicken Sie auf Mehr, um die erweiterten Einstellungen anzuzeigen.

  5. Geben Sie einen Wert in das Feld Zeitlimit ein.

Speicher

Verwenden Sie zum Festlegen des Speichers einer Funktion mit dem gcloud-Befehlszeilentool das --memory-Flag mit der Anzahl von Megabyte (128, 256, 512, 1024, 2048, 4096). Beispiel:

gcloud functions deploy FUNCTION_NAME --memory=MEMORY

Standardmäßig beträgt der jeder Funktion zugewiesene Speicher 256 MB.

Dateisystem

Die Funktionsausführungsumgebung enthält eine ausführbare Funktionsdatei sowie Dateien und Verzeichnisse, die im bereitgestellten Funktionspaket enthalten sind, z. B. lokale Abhängigkeiten. Diese Dateien sind in einem schreibgeschützten Verzeichnis enthalten, das basierend auf dem Speicherort der Funktionsdatei ermittelt werden kann. Beachten Sie, dass sich das Funktionsverzeichnis vom aktuellen Arbeitsverzeichnis unterscheiden kann.

Im folgenden Beispiel werden Dateien aufgelistet, die sich im Funktionsverzeichnis befinden:

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");
            }
        }
    }
}

Ruby

require "functions_framework"

FunctionsFramework.http "concepts_filesystem" do |_request|
  files = Dir.entries "."
  "Files: #{files.join "\n"}"
end

Sie können auch Code aus anderen mit der Funktion bereitgestellten Dateien laden.

Der einzige beschreibbare Teil des Dateisystems ist das Verzeichnis /tmp, mit dem Sie temporäre Dateien in einer Funktionsinstanz speichern können. Es handelt sich um den lokalen Datenträgerbereitstellungspunkt "tmpfs". In dieses Volume geschriebene Daten werden im Arbeitsspeicher gespeichert. Beachten Sie, dass dadurch die für die Funktion bereitgestellten Speicherressourcen belegt werden.

Der Rest des Dateisystems ist schreibgeschützt und für die Funktion zugänglich.

Netzwerk

Die Funktion kann über Standardbibliotheken der Laufzeit oder Drittanbieter auf das öffentliche Internet zugreifen. Zum Beispiel können Sie einen HTTP-Endpunkt wie folgt aufrufen:

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}'.");
            }
        }
    }
}

Ruby

require "functions_framework"
require "net/http"

FunctionsFramework.http "concepts_requests" do |_request|
  url = "example.com"
  response = Net::HTTP.get_response url, "/"
  "Received code: #{response.code} from url: #{url}"
end

Versuchen Sie, Netzwerkverbindungen in mehreren Funktionsaufrufen wiederzuverwenden, wie unter Netzwerke optimieren beschrieben. Eine Verbindung, die 2 Minuten lang nicht verwendet wurde, wird vom System möglicherweise geschlossen. Weitere Versuche, eine geschlossene Verbindung zu verwenden, führen zu einem Fehler "Verbindung zurückgesetzt". Ihr Code sollte daher entweder eine Bibliothek verwenden, die geschlossene Verbindungen verarbeiten kann, oder diese explizit behandeln, wenn Netzwerkkonstrukte auf niedriger Ebene verwendet werden.

Mehrere Funktionen

Jede bereitgestellte Funktion ist von allen anderen Funktionen isoliert, selbst wenn diese von derselben Quelldatei stammen. Sie teilen weder Arbeitsspeicher, globale Variablen, Dateisysteme noch andere Zustände.

Zum Freigeben von Daten für alle bereitgestellten Funktionen können Sie Speicherdienste wie Datastore, Firestore oder Cloud Storage verwenden. Alternativ können Sie mit den entsprechenden Triggern eine Funktion aus einer anderen aufrufen. Führen Sie zum Beispiel eine HTTP-Anfrage an den Endpunkt einer HTTP-Funktion aus oder veröffentlichen Sie eine Nachricht an ein Pub- / Sub-Thema, um eine Pub/Sub-Funktion auszulösen.