如何让云任务仅运行一次?

时间:2020-07-17 21:24:23

标签: firebase google-cloud-firestore google-cloud-tasks

我已经编写了一个云任务,它可以完美运行并触发我给出的链接而没有任何问题,但是它不会停止重试运行该链接。

我如何使其只能运行一次?

我想做的是将来在集合中写入的文档上运行一次Firestore Function。我找到了this个教程。

到目前为止,我的任务创建代码可以完美地工作,并为要调用的函数提供正确的有效负载。而且,被调用的函数在第一次运行并以状态200退出时也能正常工作。但是在重试中,由于没有数据可访问,因此我必须以错误500退出。

我可以在Firestore函数的日志中看到200和500个日志,但是即使某个方法已运行50次,Cloud Tasks的日志也为空!


这是完整的代码

import * as functions from 'firebase-functions'
import * as admin from 'firebase-admin'

const { CloudTasksClient } = require('@google-cloud/tasks')

exports.moveActivityFromPlanToRecord = () =>
    functions
    .region('europe-west1')
    .firestore.document('Users/{userId}/Activities/{activityId}')
        .onCreate(async snapshot => {

            const moveTime = snapshot.data()! as MoveTime

            if (!moveTime || !moveTime.dueTime) {
                console.log("DueTime is empty or null: \n" + moveTime)
                return
            }


            // Get the project ID from the FIREBASE_CONFIG env var
            const project = JSON.parse(process.env.FIREBASE_CONFIG!).projectId
            const location = 'europe-west1'
            const queue = 'activityDateEventChecker'

            //queuePath is going to be a string that uniquely identifes the task
            const tasksClient = new CloudTasksClient()
            const queuePath: string =
                tasksClient.queuePath(project, location, queue)

            // URL to my callback function and the contents of the payload to deliver
            const url = `https://${location}-${project}.cloudfunctions.net/activityDateEventCheckerCallback`
            const docPath = snapshot.ref.path
            const dueTime = moveTime.dueTime
            const payload: MoveTaskPayload = { docPath, dueTime }

            console.log(payload)

            // build up the configuration for the Cloud Task
            const task = {
                httpRequest: {
                    httpMethod: 'POST',
                    url: url,
                    body: Buffer.from(JSON.stringify(payload)).toString('base64'),
                    headers: {
                        'Content-Type': 'application/json',
                    },
                },
                scheduleTime: {
                    seconds: moveTime.dueTime / 1000
                }
            }

            // enqueue the task in the queue
            return tasksClient.createTask({ parent: queuePath, task: task })
        })


interface MoveTime extends admin.firestore.DocumentData {
    dueTime?: number
}
interface MoveTaskPayload {
    docPath: string,
    dueTime: number
}

exports.activityDateEventCheckerCallback = () =>
    functions
    .region('europe-west1')
    .https.onRequest(async (req, res) => {
        const payload = req.body as MoveTaskPayload
        try {
            // getting the item
            const activity = await admin.firestore().doc(payload.docPath).get()

            // if time is up for it
            if (Date.now() >= payload.dueTime && activity.data() != undefined) {
                // getting path to activity to be in record
                const pathUser = activity.ref.parent.parent?.path
                const pathDocRecord = admin.firestore().doc(`${pathUser}/Record/${activity.id}`)

                
                console.log("RECORD--  ", (await (await pathDocRecord.get()).data())?.subject)

                // moving activity into record
                await pathDocRecord.set(activity.data()!)
                await activity.ref.delete()


                // sending notif to user
                const fcmPayload = {
                    notification: {
                        title: `${activity.data()?.subject}`,
                        body: " Time for activity. Record how it goes!"
                    },
                    data: {
                        activityId: activity.id
                    }
                }

                const user = await admin.firestore().doc(pathUser!).get()
                const fcmToken: string = user.data()?.fcmToken

                return admin.messaging().sendToDevice(fcmToken, fcmPayload)
            }

            return null

        } catch (error) {
            console.error(error)
            res.status(500).send(error)
            return null
        }
    })

1 个答案:

答案 0 :(得分:1)

Cloud Task中的任务在未获得响应代码2XX时重试。

您可以使用maxAttempt参数在Cloud Task Queue中配置重试。

doc

中提到了详细信息
相关问题