functions-framework-nodejs icon indicating copy to clipboard operation
functions-framework-nodejs copied to clipboard

Support for health endpoints in cloudevents functions

Open lance opened this issue 4 years ago • 4 comments

When specifying a Container object in Kubernetes, it is possible to specify both a readinessProbe and a livenessProbe which inform the system that the application is healthy. In Knative, these endpoints may also be specified in the Container section of a Service. However, one thing that Knative does differently is that if not specified, Knative considers "container startup and listening on the declared HTTP socket" sufficient. [reference].

The implication of this is that Knative is performing a GET request to / on container startup if these health endpoints are not specified when the Service is deployed. Unfortunately, it seems this is explicitly disallowed for cloudevents. https://github.com/GoogleCloudPlatform/functions-framework-nodejs/blob/71eb43fe8e75b6939cce1ec425b84aca4014ed75/src/server.ts#L134-L138 The end result is that I cannot deploy a cloudevents function to Knative because the Service never enters the ready state. It would be nice if this framework allowed me to do any one of the following.

  • Use it in Knative for cloudevents with predetermined health endpoints
  • Use it in Knative for cloudevents with health endpoints that I can configure
  • Use it in Knative for cloudevents with support for GET /

If it is already possible somehow to do any of the above, can you please provide a doc reference - and my apologies for the oversight.

lance avatar Nov 23 '21 18:11 lance

For maximum flexibility, I recommend using the HTTP signature type for functions that need to handle broader functionality than a POST request with a binary cloudevent. I think Matt is thinking about this issue a bit more though and can provide another perspective.

I'm not sure if this feature is expected to be within scope of the Functions Framework contract / all of our languages.

grant avatar Dec 09 '21 22:12 grant

For maximum flexibility, I recommend using the HTTP signature type for functions that need to handle broader functionality than a POST request with a binary cloudevent.

The problem is that I don't see a way to deploy a CloudEvent function to Knative without this change. Perhaps I am missing something. If so, please let me know!

If health endpoints are not explicitly declared in the Service, then Knative will assume GET / is sufficient to determine if a service is healthy and running. But the framework only supports POST / for CloudEvents.

The Knative runtime contract says

The core.v1.Container object allows specifying both a readinessProbe and a livenessProbe. If not provided, container startup and listening on the declared HTTP socket is considered sufficient to declare the container "ready" and "live"

Meaning that Knative will GET / to determine if the service is healthy and capable of responding to requests. This will never work for a CloudEvent function using this framework. Is it possible for a CloudEvent function developer to expose an endpoint other than / using the framework? If so, I could expose these health probe endpoints myself. But I am not aware of a way to do that.

lance avatar Dec 10 '21 14:12 lance

Following up here.

Can you give me an exact example of what you want to do?

A HTTP function gives the maximum flexibility for handling different routes, methods, etc. On the other hand, a CE function very specifically handles a POST request to the function. Some languages are restricted by the CESDK receivers, even if we wanted to change our URL handling.

In this case, I'd recommend a function like this...

const functions = require('@google-cloud/functions-framework');

functions.http('myFunc', (req, res) => {
  if (req.method === 'GET') {
    // healthcheck
  } else {
    // handle CloudEvent
  }
});

We don't handle multiple endpoints in the FFs. We also don't support multiple function handlers or HTTP methods for CloudEvent functions.

If this workaround doesn't satisfy the request, it would help if you stated exactly what code you'd like to deploy and any needed change in the Functions Framework contract: https://github.com/GoogleCloudPlatform/functions-framework

grant avatar Mar 28 '22 23:03 grant

Can you give me an exact example of what you want to do?

I want to deploy a Node.js CloudEvent function to a vanilla Knative cluster.

I know that I could use an HTTP function, receive an incoming request, and then parse the incoming headers and body to extract the CloudEvent. But given that this framework supports CloudEvents, I would rather not do that; it shouldn't be necessary.

If this workaround doesn't satisfy the request, it would help if you stated exactly what code you'd like to deploy and any needed change in the Functions Framework contract: https://github.com/GoogleCloudPlatform/functions-framework

I am not sure how much clearer I can be. I also shared this as a problem with @jskeet in the dotnet framework, and I think he has a pretty good grasp of what I'm talking about here. https://github.com/GoogleCloudPlatform/functions-framework-dotnet/issues/231#issuecomment-1080371870

The Functions Framework is designed to be compatible with Knative environments. Just build and deploy your container to a Knative environment.

Given that the README.md states clearly that it should work with Knative, I thought it best to point out that CloudEvent functions do not work with vanilla Knative, and offer some suggestions for a fix.

To the best of my knowledge, there is no way to deploy a CloudEvent function without a modification similar to what I proposed in the original description. If you want to better understand what I mean, simply create the most basic CloudEvent function possible - echo input or something - anything really - and try deploying to a vanilla Knative cluster. Your function will never start.

lance avatar Mar 29 '22 12:03 lance