GoogleCloudPlatform / functions-framework-go

FaaS (Function as a service) framework for writing portable Go functions
https://godoc.org/github.com/GoogleCloudPlatform/functions-framework-go
Apache License 2.0
459 stars 63 forks source link

Function execute twice #181

Closed nem-vkehayov closed 1 year ago

nem-vkehayov commented 1 year ago

Hello everybody,

I need your help with an issue I'm facing. Whenever I execute my code, it runs twice and I can't figure out why. I even deployed the code to GCP Cloud Functions, but the issue persists. My automation involves adding environment variables to CloudRun instances, but now it appends the variable twice. I tried implementing a channel with Golang, but the result is still the same. Although the executions are now performed one by one instead of simultaneously.

Sample code:


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

    "github.com/GoogleCloudPlatform/functions-framework-go/functions"
)

func init() {
    functions.HTTP("HelloWorld", helloWorld)
}

// helloWorld writes "Hello, World!" to the HTTP response.
func helloWorld(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintln(w, "Hello, World!")
    log.Println("Hello")
}

Sample output:

➜  ~/go/src/gcp5 export FUNCTION_TARGET=HelloWorld
go run cmd/main.go
# Output: Serving function: HelloWorld
Serving function: "HelloWorld"

2023/03/31 15:59:47 Hello
2023/03/31 15:59:47 Hello

And yes, I am not golang dev :) Any help will be much appreciated.

garethgeorge commented 1 year ago

Hi @nem-vkehayov , did you ever get to the bottom of this?

I did a bit of investigation this morning and validated our local development docs using a sample function including a print as you had done, I'm only seeing prints that are 1:1 with invocations - It's also pretty strange that all output from your shell looks like it's getting duplicated.

nem-vkehayov commented 1 year ago

Hi @garethgeorge , thanks for checking this out.

I have a function deployed a GCP function and it's executed twice:

image
package function

import (
    "context"
    "fmt"
    "net/http"

      run "cloud.google.com/go/run/apiv2"
      runpb "cloud.google.com/go/run/apiv2/runpb"
      "github.com/GoogleCloudPlatform/functions-framework-go/functions"
    // "google.golang.org/api/option"
)

func init() {
    functions.HTTP("HelloWorld", helloWorld)
}

func helloWorld(w http.ResponseWriter, r *http.Request) {
    ctx := context.Background()

    // Set up a client to access the GCP Cloud Run API
    // c, err := run.NewServicesClient(ctx, option.WithCredentialsFile("SA_key.json"))
    c, err := run.NewServicesClient(ctx)
    if err != nil {
        fmt.Println("Failed to create Cloud Run client:", err)
        return
    }

    defer c.Close()

    req := &runpb.GetServiceRequest{
        Name: "projects/test/locations/europe-west2/services/availability-eu",
    }
    op, err := c.GetService(ctx, req)
    if err != nil {
        fmt.Printf("Unknown error  %v", err)
    }

    op.Template.Containers[0].Env = append(op.Template.Containers[0].Env, &runpb.EnvVar{
        Name: "RESTART",
        Values: &runpb.EnvVar_Value{
            Value: "RESTART1",
        },
    })

    // ************** DEFINE REQUEST2 ***************

    req2 := &runpb.UpdateServiceRequest{
        Service: op,
    }

    op2, err := c.UpdateService(ctx, req2)
    if err != nil {
        fmt.Printf("The error is %s", err.Error())
    }

    fmt.Println(op2)
}

go.mod file:

module example.com/hello

go 1.19

require (
    cloud.google.com/go/run v0.9.0
    github.com/GoogleCloudPlatform/functions-framework-go v1.7.1
    google.golang.org/api v0.114.0
)

require (
    cloud.google.com/go v0.110.0 // indirect
    cloud.google.com/go/compute v1.18.0 // indirect
    cloud.google.com/go/compute/metadata v0.2.3 // indirect
    cloud.google.com/go/functions v1.10.0 // indirect
    cloud.google.com/go/iam v0.12.0 // indirect
    cloud.google.com/go/longrunning v0.4.1 // indirect
    github.com/cloudevents/sdk-go/v2 v2.6.1 // indirect
    github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
    github.com/golang/protobuf v1.5.2 // indirect
    github.com/google/go-cmp v0.5.9 // indirect
    github.com/google/uuid v1.3.0 // indirect
    github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect
    github.com/googleapis/gax-go/v2 v2.7.1 // indirect
    github.com/json-iterator/go v1.1.10 // indirect
    github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
    github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 // indirect
    go.opencensus.io v0.24.0 // indirect
    go.uber.org/atomic v1.4.0 // indirect
    go.uber.org/multierr v1.1.0 // indirect
    go.uber.org/zap v1.10.0 // indirect
    golang.org/x/net v0.8.0 // indirect
    golang.org/x/oauth2 v0.6.0 // indirect
    golang.org/x/sys v0.6.0 // indirect
    golang.org/x/text v0.8.0 // indirect
    google.golang.org/appengine v1.6.7 // indirect
    google.golang.org/genproto v0.0.0-20230320184635-7606e756e683 // indirect
    google.golang.org/grpc v1.53.0 // indirect
    google.golang.org/protobuf v1.29.1 // indirect
)

I can see that the function is executed twice in GCP and locally.

garethgeorge commented 1 year ago

Hi @nem-vkehayov, if you follow the instructions for a known working sample i.e. https://cloud.google.com/functions/docs/create-deploy-http-go do you still see duplicated invocations?

If you go ahead and follow those docs and still see duplicated invocations I'd be interested if you can provide the cloud logs for your function as well as your invocation command.