Publish and route custom events


This tutorial shows you how to publish custom events to an Eventarc channel, filter and route events through an Eventarc trigger, and invoke a Cloud Run service. Other supported destinations are Google Kubernetes Engine (including the public endpoints of private and public services running in a GKE cluster) and Workflows.

Support for custom events allows producer services to define and raise events which are then routed to consumer services based on the filtering configured through an Eventarc trigger. The code that raises these events can run on Google Cloud compute platforms or in other cloud environments.

Eventarc acts as an event intermediary between producers and consumers of these custom events, asynchronously delivering events from event producers to consumer services, and supporting the orchestration of these decoupled services:

Custom events processing diagram

Objectives

In this tutorial, you will:

  1. Deploy an event receiver service to Cloud Run.

  2. Create an Eventarc channel as a target to publish events to.

  3. Create an Eventarc trigger that allows you to configure event routing by specifying the channel, the event attributes, and the destination.

  4. Publish a custom event to the channel by using the Eventarc Publishing API.

  5. View the event in the Cloud Run logs.

Costs

This tutorial uses the following billable components of Google Cloud:

Refer to the Eventarc pricing page for more details.

Before you begin

    Security constraints defined by your organization might prevent you from completing the following steps. For troubleshooting information, see Develop applications in a constrained Google Cloud environment.

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  3. Make sure that billing is enabled for your Google Cloud project.

  4. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  5. Make sure that billing is enabled for your Google Cloud project.

  6. Install and initialize the Google Cloud CLI.
  7. Update gcloud components:
    gcloud components update
  8. Log in using your account:
    gcloud auth login
  9. Enable the APIs:
    gcloud services enable \
    eventarc.googleapis.com \
    eventarcpublishing.googleapis.com \
    run.googleapis.com
  10. Set the configuration variables used in this tutorial:
    export REGION=LOCATION
    export PROJECT_ID=PROJECT_ID
    gcloud config set project ${PROJECT_ID}
    gcloud config set run/region ${REGION}
    gcloud config set eventarc/location ${REGION}

    Replace the following:

    • PROJECT_ID: your Google Cloud project ID.
    • LOCATION: the location of the Eventarc trigger. For this preview, only us-central1 is currently supported.
  11. Grant the eventarc.publisher role to the service account that will be used to publish events.
    PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format='value(projectNumber)')
    gcloud projects add-iam-policy-binding PROJECT_ID \
        --member=serviceAccount:$PROJECT_NUMBER-compute@developer.gserviceaccount.com \
        --role='roles/eventarc.publisher'

    This tutorial uses the default Compute Engine service account. We recommend using the default service account for testing and development only.

    Or, you can create a user-managed service account and then grant it the eventarc.publisher role:

    PUBLISHER_SA=SA_NAME
    gcloud iam service-accounts create ${PUBLISHER_SA}

    Replace SA_NAME with the name of the service account. It must be between 6 and 30 characters, and can contain lowercase alphanumeric characters and dashes. After you create a service account, you cannot change its name.

Deploy an event receiver to Cloud Run

Using a prebuilt image, gcr.io/cloudrun/hello, deploy a Cloud Run service that will receive and log events. For more information, see Deploying container images.

gcloud run deploy helloworld-service \
    --image=gcr.io/cloudrun/hello \
    --allow-unauthenticated \
    --region=us-central1

When you see the service URL, the deployment is complete.

Create a channel

A channel is a Google Cloud resource that is used as a pipeline to deliver custom events from producers to consumers. Custom events are published to a channel and an Eventarc trigger subscribes to those events.

Create a channel to support the integration between producers and consumers of custom events:

gcloud eventarc channels create CHANNEL_ID

Replace CHANNEL_ID with the resource name for the channel. For example: helloworld-channel.

Retrieve channel properties

After creating a channel, you can retrieve the channel properties and confirm that it is active:

gcloud eventarc channels describe CHANNEL_ID

The output is similar to the following:

createTime: '2022-04-26T20:46:06.113533183Z'
name: projects/your-project-123/locations/us-central1/channels/helloworld-channel
pubsubTopic: projects/your-project-123/topics/eventarc-channel-us-central1-helloworld-channel-465
state: ACTIVE
uid: 86391a0b-a264-4172-a3b5-a893179f1d1a
updateTime: '2022-04-26T20:46:10.106938915Z'

Create a trigger using the gcloud CLI

An Eventarc trigger declares your interest in a certain event or set of events. You can configure event routing by specifying filters for the trigger, including the channel and a destination.

Eventarc supports filtering on any CloudEvents attribute specified by the custom event producer.

You can create a trigger by running a gcloud command along with required and optional flags. Requests to the follow destinations are triggered according to the filters.

Cloud Run

gcloud eventarc triggers create TRIGGER \
    --channel=CHANNEL_ID \
    --destination-run-service=DESTINATION_RUN_SERVICE \
    --destination-run-region=DESTINATION_RUN_REGION \
    --event-filters=type=EVENT_TYPE \
    --service-account=$PROJECT_NUMBER-compute@developer.gserviceaccount.com

Replace the following:

  • TRIGGER: the ID of the trigger or a fully qualified identifier.
  • CHANNEL_ID: a name for the channel. For more information, in this document, see Create a channel.
  • DESTINATION_RUN_SERVICE: the name of the Cloud Run service that receives the events for the trigger. The service must be in the same region as the trigger, unless the trigger's location is global. The service must be in the same project as the trigger and will receive events as HTTP POST requests sent to its root URL path (/), whenever the event is generated.
  • DESTINATION_RUN_REGION: the region in which the destination Cloud Run service can be found. If not specified, it is assumed that the service is in the same region as the trigger.
  • EVENT_TYPE: the type of event supported by the producer. Each trigger can have multiple event filters, comma delimited in one --event-filters=[ATTRIBUTE=VALUE,...] flag, or you can repeat the flag to add more filters. Only events that match all the filters are sent to the destination. Wildcards and regular expressions are not supported.

Example:

gcloud eventarc triggers create helloworld-trigger \
    --channel=helloworld-channel \
    --destination-run-service=helloworld-service \
    --destination-run-region=us-central1 \
    --event-filters=type=mycompany.myorg.myproject.v1.myevent \
    --event-filters=someAttr=foo \
    --service-account=$PROJECT_NUMBER-compute@developer.gserviceaccount.com

This creates a trigger called helloworld-trigger for the specified custom events, and routes those events using the helloworld-channel to the Cloud Run helloworld-service. Note that although your trigger is created immediately, it can take up to two minutes for a trigger to be fully functional.

GKE

gcloud eventarc triggers create TRIGGER \
    --channel=CHANNEL_ID \
    --destination-gke-cluster=DESTINATION_GKE_CLUSTER \
    --destination-gke-location=DESTINATION_GKE_LOCATION \
    --destination-gke-namespace=DESTINATION_GKE_NAMESPACE \
    --destination-gke-service=DESTINATION_GKE_SERVICE \
    --destination-gke-path=DESTINATION_GKE_PATH \
    --event-filters=type=EVENT_TYPE \
    --service-account=$PROJECT_NUMBER-compute@developer.gserviceaccount.com

Replace the following:

  • TRIGGER: the ID of the trigger or a fully qualified identifier.
  • CHANNEL_ID: a name for the channel. For more information, in this document, see Create a channel.
  • DESTINATION_GKE_CLUSTER: the name of the GKE cluster in which the target GKE service that receives events is running.
  • DESTINATION_GKE_LOCATION: the location in which the destination GKE service can be found. If not specified, it is assumed that the service is in the same region as the trigger. For more information see Knative serving locations.
  • DESTINATION_GKE_NAMESPACE: the namespace in which the destination GKE service is running. If not specified, the default namespace is used.
  • DESTINATION_GKE_SERVICE: the name of the GKE service that receives the events for the trigger. The service must be in the same region as the trigger, unless the trigger's location is global. The service must be in the same project as the trigger and will receive events as HTTP POST requests sent to its root URL path (/), whenever the event is generated.
  • (Optional) DESTINATION_GKE_PATH: the relative path you specify on the destination GKE service to which the events for the trigger should be sent. For example: /, /route, route, route/subroute.
  • EVENT_TYPE: the type of event supported by the producer. Each trigger can have multiple event filters, comma delimited in one --event-filters=[ATTRIBUTE=VALUE,...] flag, or you can repeat the flag to add more filters. Only events that match all the filters are sent to the destination. Wildcards and regular expressions are not supported.

Example:

gcloud eventarc triggers create helloworld-trigger \
    --channel=helloworld-channel \
    --destination-gke-cluster=gke-events-cluster \
    --destination-gke-location=us-central1-a \
    --destination-gke-namespace=default \
    --destination-gke-service=helloworld-service \
    --destination-gke-path=/ \
    --event-filters=type=mycompany.myorg.myproject.v1.myevent \
    --event-filters=someAttr=foo \
    --service-account=$PROJECT_NUMBER-compute@developer.gserviceaccount.com

This creates a trigger called helloworld-trigger for the specified custom events, and routes those events using the helloworld-channel to the GKE helloworld-service.

Workflows

gcloud eventarc triggers create TRIGGER \
    --channel=CHANNEL_ID \
    --destination-workflow=DESTINATION_WORKFLOW \
    --destination-workflow-location=DESTINATION_WORKFLOW_LOCATION \
    --event-filters=type=EVENT_TYPE \
    --service-account=$PROJECT_NUMBER-compute@developer.gserviceaccount.com

Replace the following:

  • TRIGGER: the ID of the trigger or a fully qualified identifier.
  • CHANNEL_ID: a name for the channel. For more information, in this document, see Create a channel.
  • DESTINATION_WORKFLOW: the ID of the deployed workflow that receives the events from the trigger. The workflow can be in any of the Workflows supported locations and does not need to be in the same location as the trigger. However, the workflow must be in the same project as the trigger.
  • DESTINATION_WORKFLOW_LOCATION (optional): the location in which the destination workflow is deployed. If not specified, it is assumed that the workflow is in the same location as the trigger.
  • EVENT_TYPE: the type of event supported by the producer. Each trigger can have multiple event filters, comma delimited in one --event-filters=[ATTRIBUTE=VALUE,...] flag, or you can repeat the flag to add more filters. Only events that match all the filters are sent to the destination. Wildcards and regular expressions are not supported.

Example:

gcloud eventarc triggers create helloworld-trigger \
    --channel=helloworld-channel \
    --destination-workflow=helloworld-workflow \
    --destination-workflow-location=us-central1 \
    --event-filters=type=mycompany.myorg.myproject.v1.myevent \
    --event-filters=someAttr=foo \
    --service-account=$PROJECT_NUMBER-compute@developer.gserviceaccount.com

This creates a trigger called helloworld-trigger for the specified custom events, and routes those events using the helloworld-channel to the Workflows helloworld-workflow.

Publish events

Once a channel exists, custom events can be published directly to that channel by the events producer using the Eventarc Publishing API. There are several ways that you can do this.

Publish using the gcloud CLI

You can publish custom events to a channel using the gcloud CLI.

gcloud eventarc channels publish CHANNEL_ID \
    --event-id=EVENT_ID \
    --event-type=CUSTOM_EVENT_TYPE \
    --event-attributes=CUSTOM_EVENT_ATTRIBUTE \
    --event-source=gcloud \
    --event-data="{ EVENT_DATA }"

Replace the following:

  • EVENT_ID: the event ID
  • CUSTOM_EVENT_TYPE: the event type
  • CUSTOM_EVENT_ATTRIBUTE: event attributes
  • CUSTOM_EVENT_DATA: any arbitrary, valid JSON data

Example:

gcloud eventarc channels publish helloworld-channel \
    --event-id=12345 \
    --event-type=mycompany.myorg.myproject.v1.myevent \
    --event-attributes=someAttr=foo \
    --event-source=gcloud \
    --event-data="{\"message\" : \"Hello world from gcloud\"}"

You should see an Event published successfully message.

Publish using curl

You can publish custom events to a channel using curl commands. The following example uses an access token generated by the gcloud CLI.

curl -H "Authorization: Bearer $(gcloud auth print-access-token)" \
  -H "Content-Type: application/json" \
  -H "X-Goog-User-Project: $PROJECT_ID" \
  -X POST \
  -d '{
       "events": [
             {
              "@type": "type.googleapis.com/io.cloudevents.v1.CloudEvent",
              "attributes": {
                "datacontenttype": {"ceString": "application/json"},
                "someattribute": {"ceString": "somevalue"},
                "time": {"ceTimestamp": "2022-03-19T21:29:13.899-04:00"}
              },
              "id": "12345",
              "source": "curl",
              "specVersion": "1.0",
              "textData": "{\"message\": \"Hello world from curl\"}",
              "type": "mycompany.myorg.myproject.v1.myevent"
            }
          ]
      }' \
  https://eventarcpublishing.googleapis.com/v1/projects/$(gcloud config get-value project)/locations/us-central1/channels/helloworld-channel:publishEvents

Publish using client libraries

For C# and Java, the CloudEvents SDK can be used to generate an event, convert it to a protobuf schema, and then publish it to the API.

During this preview, for other languages, you must define an event using a compiled CloudEvents proto file or by compiling your own based on the CloudEvents spec; you can then publish custom events to a channel using client libraries. (Note that the CloudEvents proto file must be included.) Protobuf schema is the preferred method of publishing events unless the schema is not supported.

  1. Take a look at the samples.

    C#

    You can publish events in the protobuf or JSON schema.

    using Google.Cloud.Eventarc.Publishing.V1;
    using CloudNative.CloudEvents;
    using CloudNative.CloudEvents.Protobuf;
    using CloudNative.CloudEvents.SystemTextJson;
    using System.Net.Mime;
    using Newtonsoft.Json;
    using Google.Protobuf.WellKnownTypes;
    
    var commandArgs = Environment.GetCommandLineArgs();
    var ProjectId = commandArgs[1];
    var Region = commandArgs[2];
    var Channel = commandArgs[3];
    // Controls the format of events sent to Eventarc.
    // 'true' for using text format.
    // 'false' for proto (preferred) format.
    bool UseTextEvent = commandArgs.Length > 4 ? bool.TryParse(commandArgs[4], out UseTextEvent) : false;
    
    var FullChannelName = $"projects/{ProjectId}/locations/{Region}/channels/{Channel}";
    Console.WriteLine($"Channel: {FullChannelName}");
    Console.WriteLine($"UseTextEvent: {UseTextEvent}");
    
    var publisherClient = await PublisherClient.CreateAsync();
    
    //Construct the CloudEvent and set necessary attributes.
    var cloudEventAttributes = new[]
    {
        CloudEventAttribute.CreateExtension("someattribute", CloudEventAttributeType.String)
    };
    
    var cloudEvent = new CloudEvent(cloudEventAttributes)
    {
        Id = Guid.NewGuid().ToString(),
        // Note: Type has to match with the trigger!
        Type = "mycompany.myorg.myproject.v1.myevent",
        Source = new Uri("urn:csharp/client/library"),
        DataContentType = MediaTypeNames.Application.Json,
        Data = JsonConvert.SerializeObject(new { Message = "Hello World from C#"}),
        Time = DateTimeOffset.UtcNow,
        // Note: someattribute and somevalue have to match with the trigger!
        ["someattribute"] = "somevalue",
    };
    
    PublishEventsRequest request;
    
    if (UseTextEvent)
    {
        // Convert the CloudEvent to JSON
        var formatter = new JsonEventFormatter();
        var cloudEventJson = formatter.ConvertToJsonElement(cloudEvent).ToString();
        Console.WriteLine($"Sending CloudEvent: {cloudEventJson}");
        request = new PublishEventsRequest
        {
            Channel = FullChannelName,
            TextEvents = { cloudEventJson }
        };
    }
    else
    {
        // Convert the CloudEvent to Proto
        var formatter = new ProtobufEventFormatter();
        var cloudEventProto = formatter.ConvertToProto(cloudEvent);
        Console.WriteLine($"Sending CloudEvent: {cloudEventProto}");
        request = new PublishEventsRequest
        {
            Channel = FullChannelName,
            Events = { Any.Pack(cloudEventProto) }
        };
    }
    
    var response = await publisherClient.PublishEventsAsync(request);
    Console.WriteLine("Event published!");
    

    Java

    You can publish events in the protobuf or JSON schema.

    package com.google.cloud.eventarc.publishing.example;
    
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.google.cloud.eventarc.publishing.v1.PublishEventsRequest;
    import com.google.cloud.eventarc.publishing.v1.PublishEventsResponse;
    import com.google.cloud.eventarc.publishing.v1.PublisherClient;
    import com.google.protobuf.Any;
    
    import io.cloudevents.CloudEvent;
    import io.cloudevents.core.provider.EventFormatProvider;
    import io.cloudevents.core.v1.CloudEventBuilder;
    import io.cloudevents.jackson.JsonCloudEventData;
    import io.cloudevents.jackson.JsonFormat;
    import io.cloudevents.protobuf.ProtobufFormat;
    
    import java.net.URI;
    import java.time.OffsetDateTime;
    import java.util.UUID;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    
    public class PublishEventsExample {
    
      static Logger LOGGER = Logger.getLogger(PublishEventsExample.class.getName());
    
      /**
       * CustomMessage represents a payload delivered as a content of the CloudEvent.
       */
      class CustomMessage {
        public CustomMessage(String message) {
          this.message = message;
        }
    
        public String message;
      }
    
      private PublishEventsRequest GetPublishEventsRequestWithTextFormat(String channelName, CloudEvent event) {
    
        byte[] serializedEvent = EventFormatProvider.getInstance()
            .resolveFormat(JsonFormat.CONTENT_TYPE)
            .serialize(event);
        String textEvent = new String(serializedEvent);
    
        PublishEventsRequest request = PublishEventsRequest.newBuilder()
            .setChannel(channelName)
            .addTextEvents(textEvent)
            .build();
    
        return request;
      }
    
      private PublishEventsRequest GetPublishEventsRequestWithProtoFormat(String channelName, CloudEvent event) throws Exception {
    
        byte[] serializedEvent = EventFormatProvider.getInstance()
            .resolveFormat(ProtobufFormat.PROTO_CONTENT_TYPE)
            .serialize(event);
    
        io.cloudevents.v1.proto.CloudEvent protoEvent = io.cloudevents.v1.proto.CloudEvent.parseFrom(serializedEvent);
        Any wrappedEvent = Any.pack(protoEvent);
    
        PublishEventsRequest request = PublishEventsRequest.newBuilder()
            .setChannel(channelName)
            .addEvents(wrappedEvent)
            .build();
    
        return request;
      }
    
      public void PublishEvent(String channelName, boolean useTextEvent) throws Exception {
    
        CustomMessage eventData = new CustomMessage("Hello world from Java");
    
        LOGGER.log(Level.INFO, "Building CloudEvent");
    
        ObjectMapper objectMapper = new ObjectMapper();
        CloudEvent event = new CloudEventBuilder()
            .withId(UUID.randomUUID().toString())
            .withSource(URI.create("//custom/from/java"))
            // Note: Type has to match with the trigger!
            .withType("mycompany.myorg.myproject.v1.myevent")
            .withTime(OffsetDateTime.now())
            // Note: someattribute and somevalue have to match with the trigger!
            .withExtension("someattribute", "somevalue")
            .withExtension("extsourcelang", "java")
            .withData("application/json",
                JsonCloudEventData.wrap(objectMapper.valueToTree(eventData)))
            .build();
    
    
        PublishEventsRequest request = useTextEvent ?
          GetPublishEventsRequestWithTextFormat(channelName, event) :
          GetPublishEventsRequestWithProtoFormat(channelName, event);
    
        LOGGER.log(Level.INFO, "Publishing message to Eventarc");
    
        try {
          PublisherClient client = PublisherClient.create();
          PublishEventsResponse response = client.publishEvents(request);
          LOGGER.log(Level.INFO, String.format("Message published successfully.\nReceived response: %s",
              response.toString()));
        } catch (Exception ex) {
          LOGGER.log(Level.SEVERE, "An exception occurred while publishing", ex);
        }
      }
    
      public static void main(String[] args) throws Exception {
        String projectId = args[0];
        String region = args[1];
        String channel = args[2];
        // Controls the format of events sent to Eventarc.
        // 'true' for using text format.
        // 'false' for proto (preferred) format.
        boolean useTextEvent = args.length > 3 ? Boolean.parseBoolean(args[3]) : false;
    
        String channelName = "projects/" + projectId + "/locations/" + region + "/channels/" + channel;
        System.out.println("Channel: " + channelName);
        System.out.println("useTextEvent: " + useTextEvent);
    
        new PublishEventsExample().PublishEvent(channelName, useTextEvent);
      }
    }

    Node.js

    You can publish events only in the JSON schema.

    const { CloudEvent } = require('cloudevents');
    const { PublisherClient } = require('@google-cloud/eventarc-publishing');
    
    /**
     * Builds a CloudEvent to publish to an Eventarc channel.
     *
     * @returns Fully constructed CloudEvent
     */
    const BuildCloudEvent = () => {
       return new CloudEvent({
         type: "mycompany.myorg.myproject.v1.myevent",
         source: "//event/from/nodejs",
         data: {
            message: "Hello World from Node.js"
         },
         datacontenttype: "application/json",
         time: new Date().toISOString(),
         // Note: someattribute and somevalue have to match with the trigger!
         someattribute: 'somevalue'
         });
     }
    
    /**
     * Publish event to the channel with the Eventarc publisher client.
     *
     * @param {string} channel
     * @param {CloudEvent} event
     */
    const publishEventToChannel = async (channel, event) => {
        // Instantiates a client with default credentials and options.
        const publishingClient = new PublisherClient();
    
        // Construct publish request.
        const request = {
            channel: channel,
            // Prepare text event rather than proto representation.
            // Since NodeJS CloudEvents SDK doesn't have method to transform
            // the object to protobuf it's easier to send the text representation.
            textEvents: [
                JSON.stringify(event)
            ]
        };
        console.log("Constructed the request with the event: ", request);
    
        // Publish event
        try {
            const response = await publishingClient.publishEvents(request);
            console.log("Received response: ", response);
        } catch (e) {
            console.error("Received error from publishing API: ", e);
        }
    }
    
    const arguments = process.argv.slice(2);
    const channel = arguments[0];
    if (!channel) {
        console.error("Missing channel, please pass it in the argument in the form of projects/$PROJECT_ID/locations/$REGION/channels/$CHANNEL_NAME")
        return;
    }
    
    const event = BuildCloudEvent();
    
    publishEventToChannel(channel, event);
    

    Python

    You can publish events only in the JSON schema.

    import sys
    import argparse
    import logging
    
    from cloudevents.http import CloudEvent
    from cloudevents.conversion import to_json
    from google.cloud.eventarc_publishing_v1.types import publisher
    from google.cloud.eventarc_publishing_v1.services.publisher import client
    
    parser = argparse.ArgumentParser(description="Arguments to publish an event with Eventarc Publisher API")
    parser.add_argument('--channel', type=str, help='Name of the channel on which the event should be published')
    parser.add_argument('--log', type=str, choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'], default='ERROR')
    
    logger = logging.getLogger()
    console_handler = logging.StreamHandler(sys.stdout)
    logger.addHandler(console_handler)
    
    def main():
      args = parser.parse_args()
      logger.setLevel(args.log)
    
      # Build a valid CloudEvent
      # The CloudEvent "id" and "time" are auto-generated if omitted and "specversion" defaults to "1.0".
      attributes = {
          "type": "mycompany.myorg.myproject.v1.myevent",
          "source": "//event/from/python",
          "datacontenttype": "application/json",
          # Note: someattribute and somevalue have to match with the trigger!
          "someattribute": "somevalue"
      }
      data = {"message": "Hello World from Python"}
      event = CloudEvent(attributes, data)
    
      logger.debug('Prepared CloudEvent:')
      logger.debug(event)
    
      request = publisher.PublishEventsRequest()
      request.channel = args.channel
      request.text_events.append(to_json(event))
    
      logger.debug('Prepared publishing request:')
      logger.debug(request);
    
      publisher_client = client.PublisherClient()
      response = publisher_client.publish_events(request)
      logger.info('Event published')
      logger.debug(f'Result: {response}')
    
    
    if __name__ == '__main__':
      main()
  2. Invoke the samples using the JSON schema.

    C#

    PROJECT_ID=$(gcloud config get-value project)
    REGION=us-central1
    CHANNEL_ID=helloworld-channel
    
    dotnet run $PROJECT_ID $REGION $CHANNEL_ID true
    

    Java

    PROJECT_ID=$(gcloud config get-value project)
    REGION=us-central1
    CHANNEL_ID=helloworld-channel
    
    ./gradlew run --args="$PROJECT_ID $REGION $CHANNEL_NAME true"
    

    Node.js

    PROJECT_ID=$(gcloud config get-value project)
    REGION=us-central1
    CHANNEL_ID=helloworld-channel
    
    npm run invoke projects/$PROJECT_ID/locations/$REGION/channels/$CHANNEL_NAME
    

    Python

    PROJECT_ID=$(gcloud config get-value project)
    REGION=us-central1
    CHANNEL_ID=helloworld-channel
    
    python3 publish.py \
        --channel projects/$PROJECT_ID/locations/$REGION/channels/$CHANNEL_NAME \
        --log=DEBUG
    

View the custom event in the logs

Publishing a custom event to the Eventarc channel triggers the Cloud Run service. You can view the event-related log entries created by your Cloud Run service:

gcloud logging read "resource.type=cloud_run_revision AND resource.labels.service_name=SERVICE_NAME" --limit 5

Replace SERVICE_NAME with the name of your Cloud Run service.

The log entry should be similar to the following (Hello world from gcloud, Hello world from curl, Hello world from Python, and so on):

jsonPayload:
  event:
    data:
      message: Hello world from gcloud
    datacontenttype: application/json
    id: '12345'
    someattr: foo
    source: gcloud
    specversion: '1.0'
    time: '2022-04-27T14:04:28.586Z'
    type: mycompany.myorg.myproject.v1.myevent
  eventType: mycompany.myorg.myproject.v1.myevent
  message: 'Received event of type mycompany.myorg.myproject.v1.myevent. Event data:
    {"message" : "Hello world from gcloud"}'

Logs might take a few moments to appear. If you don't see them immediately, check again after a minute.

Clean up

If you created a new project for this tutorial, delete the project. If you used an existing project and want to keep it without the changes added in this tutorial, delete the resources created for the tutorial.

Delete the project

The easiest way to eliminate billing is to delete the project that you created for the tutorial.

To delete the project:

  1. In the Google Cloud console, go to the Manage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

Delete tutorial resources

  1. Delete the Cloud Run service you deployed in this tutorial:

    gcloud run services delete SERVICE_NAME

    Where SERVICE_NAME is your chosen service name.

    You can also delete Cloud Run services from the Google Cloud console.

  2. Remove any gcloud CLI default configurations you added during the tutorial setup.

    For example:

    gcloud config unset run/region

    or

    gcloud config unset project

  3. Delete other Google Cloud resources created in this tutorial:

    • Delete the Eventarc trigger:

      gcloud eventarc triggers delete TRIGGER_NAME
      
      Replace TRIGGER_NAME with the name of your trigger.

    • Delete the Eventarc channel:

      gcloud eventarc channels delete CHANNEL_ID
      
      Replace CHANNEL_ID with the name of your channel.

What's next