2

Description:

I have created a Firebase app where a user can insert a Firestore document. When this document is created a timestamp is added so that it can be automatically deleted after x amount of time, by a cloud function.

After the document is created, a http/onCreate cloud function is triggered successfully, and it creates a cloud task. Which then deletes the document on the scheduled time.

export const onCreatePost = functions
  .region(region)
  .firestore.document('/boxes/{id}')
  .onCreate(async (snapshot) => {
    const data = snapshot.data() as ExpirationDocData;
    // Box creation timestamp.
    const { timestamp } = data;
    // The path of the firebase document('/myCollection/{docId}').
    const docPath = snapshot.ref.path;
    await scheduleCloudTask(timestamp, docPath)
      .then(() => {
        console.log('onCreate: cloud task created successfully.');
      })
      .catch((error) => {
        console.error(error);
      });
  });

export const scheduleCloudTask = async (timestamp: number, docPath: string) => {
  // Convert timestamp to seconds.
  const timestampToSeconds = timestamp / 1000;
  // Doc time to live in seconds
  const documentLifeTime = 20;
  const expirationAtSeconds = timestampToSeconds + documentLifeTime;
  // The Firebase project ID.
  const project = 'my-project';
  // Cloud Tasks -> firestore time to life queue.
  const queue = 'my-queue';
  const queuePath: string = tasksClient.queuePath(project, region, queue);
  // The url to the callback function.
  // That gets envoked by Google Cloud tasks when the deadline is reached.
  const url = `https://${region}-${project}.cloudfunctions.net/callbackFn`;
  const payload: ExpirationTaskPayload = { docPath };
  // Google cloud IAM & ADMIN principle account.
  const serviceAccountEmail = 'myServiceAccount@appspot.gserviceaccount.com';
  // Configuration for the Cloud Task
  const task = {
    httpRequest: {
      httpMethod: 'POST',
      url,
      oidcToken: {
        serviceAccountEmail,
      },
      body: Buffer.from(JSON.stringify(payload)).toString('base64'),
      headers: {
        'Content-Type': 'application/json',
      },
    },
    scheduleTime: {
      seconds: expirationAtSeconds,
    },
  };
  await tasksClient.createTask({
    parent: queuePath,
    task,
  });
};


export const callbackFn = functions
  .region(region)
  .https.onRequest(async (req, res) => {
    const payload = req.body as ExpirationTaskPayload;
    try {
      await admin.firestore().doc(payload.docPath).delete();
      res.sendStatus(200);
    } catch (error) {
      console.error(error);
      res.status(500).send(error);
    }
  });

Problem:

The user can also extend the time to live for the document. When that happens the timestamp is successfully updated in the Firestore document, and a http/onUpdate cloud function runs like expected.

Like shown below I tried to update the cloud tasks "time to live", by calling again
the scheduleCloudTask function. Which obviously does not work and I guess just creates another task for the document.


export const onDocTimestampUpdate = functions
  .region(region)
  .firestore.document('/myCollection/{docId}')
  .onUpdate(async (change, context) => {
    const before = change.before.data() as ExpirationDocData;
    const after = change.after.data() as ExpirationDocData;
    if (before.timestamp < after.timestamp) {
      const docPath = change.before.ref.path;
      await scheduleCloudTask(after.timestamp, docPath)
        .then((res) => {
          console.log('onUpdate: cloud task created successfully.');
          return;
        })
        .catch((error) => {
          console.error(error);
        });
    } else return;
  });

I have not been able to find documentation or examples where an updateTask() or a similar method is used to update an existing task.

Should I use the deleteTask() method and then use the createTask() method and create a new task after the documents timestamp is updated?

Thanks in advance, Cheers!

GRos
  • 21
  • 2

1 Answers1

2

Yes, that's how you have to do it. There is no API to update a task.

Doug Stevenson
  • 297,357
  • 32
  • 422
  • 441