Gust
Gust

Reputation: 96

How to run a firebase cloud function that takes 40min to execute?

I am looking for a solution to run a function that takes 40min to execute. I saw in the docs that a HTTP function can run up to 60min. So I created a function "enqueue_task" that creates a CloudTask that invokes my "long running function". In the simulator I can run "enqueue_task" and it works, but when I deploy this function I get the exception "400 Request contains an invalid argument"

from firebase_functions import firestore_fn, https_fn

# The Firebase Admin SDK to access Cloud Firestore.
from firebase_admin import initialize_app, firestore, functions
import google.cloud.firestore

# Dependencies for task queue functions.
from google.cloud import tasks_v2
# import requests
from firebase_functions.options import RetryConfig, RateLimits, SupportedRegion
from google.auth.transport.requests import AuthorizedSession
import os, json
from dotenv import load_dotenv
import traceback

@https_fn.on_request()
def enqueue_task(req: https_fn.Request) -> https_fn.Response:
    """Adds tasks to a Cloud Tasks queue."""

    credentials, _ = google.auth.default(
        scopes=["https://www.googleapis.com/auth/cloud-platform"])
    print("service account:", credentials.service_account_email)

    # this is the URL of my long running task
    url = "https://addmessage-XXXXX-uc.a.run.app/addmessage?text=nodanoda44444"

    # Create a Cloud Tasks client.
    client = tasks_v2.CloudTasksClient()
    parent = client.queue_path(project=app.project_id, location="us-central1", queue="q-teste")

    task = {
        "http_request": {  # Specify the type of request.
            "http_method": tasks_v2.HttpMethod.POST,
            "url": url,
            "oidc_token": {
                "service_account_email": credentials.service_account_email
            },
        }
    }

    # Use the client to build and send the task.
    try:
        response = client.create_task(parent=parent, task=task)
        print(f"Created task {response.name}")
        return https_fn.Response(f"Created task {response.name}")
    except Exception as e:
        print(f"Error creating task {e}")
        print(traceback.format_exc())
        return https_fn.Response(f"Error creating task ", status=400)

When I run in the emulator I am able to call my long running function, but the deployed version says "400 Request contains an invalid argument"

The line with the error is: response = client.create_task(parent=parent, task=task)

Upvotes: 0

Views: 84

Answers (1)

Gust
Gust

Reputation: 96

The problem seems to be permission, I was able to set a new service account and worked with the following code

from google.oauth2 import service_account

encoded_cred = os.environ.get('ALT_ACCOUNT')
decoded_cred = base64.b64decode(encoded_cred)
alt_account = json.loads(decoded_cred.decode('utf-8'))
alt_credentials = service_account.Credentials.from_service_account_info(alt_account)

Now in my function I call

client = tasks_v2.CloudTasksClient(credentials=alt_credentials)

I was able add the task to the queue, but the task has a max timeout of 30s so seems to not be possible to run a long function.

Upvotes: 1

Related Questions