firebase/functions-samples

[DOCS] for sample: taskqueues-backup-images, it simply doesn't work with tasks_fn.on_task_dispatched function, only with http_fn.on_request function

vitoras opened this issue · 5 comments

Which sample?

Sample name or URL [Link to closest heading](https://firebase.google.com/docs/functions/task-functions?hl=en-us)

What is the issue with this sample's docs?

Following the code example pretty straightforward but changing the on_task_dispatched functions to simply return a "Hello world"
gives a "The request was not authorized to invoke this service" 401 error when invoking a tasks functions from a task queue.

I absolutely attempted granting all imaginable roles (cloud functions invoker, cloud run invoker, etc etc) to every service account, I tried setting oidcToken with and without the "aud" key, and setting the audience with the task functions url and and project id (because for some reason it gives an error saying it was expecting the project id in the audience key, despite every single documentation saying the you should use the functions url).

Even when calling it directly from the cloud shell, it gives an error saying "Callable request verification failed: $[('Auth token was rejected.', {'app': 'MISSING', 'auth': 'INVALID', 'logging.googleapis.com/labels': {'firebase-log-type': 'callable-request-verification'}})]"

The only thing that made it work whas change the functions to an http_fn;on_request functions, but then I won't be able to set any rety or rate limit configuration, which is kind of one of the major benefits of using a task queue.

Seriously, what am I (or the docs) doing wrong?

I'm also having trouble getting the on_task_dispatched to work. I've been using the same service account key and adding a bunch of roles. I keep seeing 401 or 403 errors in the logs and also errors with the oidc token:

  • Auth token was rejected.', {'app': 'MISSING', 'auth': 'INVALID', 'logging.googleapis.com/labels': {'firebase-log-type': 'callable-request-verification'}}

  • Error validating token: Firebase ID token has incorrect "iss" (issuer) claim. Expected "https://securetoken.google.com/" but got "https://accounts.google.com".

  • Error validating token: Firebase ID token has incorrect "aud" (audience) claim. Expected "" but got "https://-xxxxxxxx-uc.a.run.app".

I'm guessing that on_task_dispatched is supposed to handle all this behind the scenes, but it's not clear what i'm supposed to do. I might also give up on the on_task_dispatched and use on_request.

I got it working using the default credentials. I believe the default credentials are coming from the same service account (auto-created by Firebase) that runs these gen 2 cloud functions. For me, this service account has a principal of something like: 0000000000000-compute@developer.gserviceaccount.com
I notice that one of the roles attached to this service account is "Editor" which gives it all the Cloud Tasks permission (and much more). Maybe that's the reason why I didn't need to add any IAM roles? I also had to use SupportedRegion.US_CENTRAL1.value ("us-central1") instead of SupportedRegion.US_CENTRAL1, which becomes something like "supportedregion.us_central1" when converted to a string.

@tasks_fn.on_task_dispatched(retry_config=options.RetryConfig(max_attempts=5, min_backoff_seconds=10),
                             rate_limits=options.RateLimits(max_concurrent_dispatches=10))
def populateReportTableCell(req: tasks_fn.CallableRequest) -> str:
    """Populates a cell in the report table."""
    print("inside populateReportTableCell")
    return "Hello from populateReportTableCell!"

@https_fn.on_call(memory=options.MemoryOption.MB_512)
def enqueue_report_gen_tasks(req: https_fn.CallableRequest):
    """Adds tasks to a Cloud Tasks queue."""
    tasks_client = tasks_v2.CloudTasksClient()
    task_queue = tasks_client.queue_path("myprojectid", 
                                         options.SupportedRegion.US_CENTRAL1.value,
                                         "populateReportTableCell")
    
    target_uri = get_function_url("populateReportTableCell")
    body = {"data": "test_data"}

    http_request = tasks_v2.HttpRequest(
        http_method=tasks_v2.HttpMethod.POST,
        url=target_uri,
        headers= {
            "Content-type": "application/json"
            },
        body=json.dumps(body).encode()
    )
    task = tasks_v2.Task(http_request=http_request)
    tasks_client.create_task(parent=task_queue, task=task)

    return "Hello from enqueue_report_gen_tasks!"

I couldn't get this to work with another (non-default) service account because I kept getting "token" errors like in my previous comment. Maybe that would involve setting the service_account option in on_task_dispatched and on_call?...

Another thing, if you get this error:

The request was not authenticated. Either allow unauthenticated invocations or set the proper Authorization header.

you need to select "Allow unauthenticated invocations" in the GCP console in Cloud Run -> your cloud function -> Security tab -> Authentication.

If you are using python and following the docs/snippets there is a major error on them

def get_function_url(name: str, location: str = SupportedRegion.US_CENTRAL1) -> str:

You need to use the value of the enum instead of passing the enum itself, otherwise the URL to create the task and find the function is wrong!

So instead of SupportedRegion.US_CENTRAL1 use SupportedRegion.US_CENTRAL1.value

Does anyone have a working example using a service account? Sure, we can turn off the auth. But that's probably not good practice.