Skip to content

Instantly share code, notes, and snippets.

@AdnanKhan45
Last active June 25, 2023 07:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AdnanKhan45/16ffa5d8d49cdf064da4469c05dd2e40 to your computer and use it in GitHub Desktop.
Save AdnanKhan45/16ffa5d8d49cdf064da4469c05dd2e40 to your computer and use it in GitHub Desktop.
Schedule Cloud Functions with Cloud Tasks (for Document TTL) Part 1
import * as functions from 'firebase-functions'
import * as admin from 'firebase-admin'
const { CloudTasksClient } = require('@google-cloud/tasks')
import { OAuth2Client } from “google-auth-library”;
admin.initializeApp()
export const onCreateEvent = functions.firestore.document("/events/${eventId}").onCreate(async snapshot => {
const data = snapshot.data() as { expireSeconds: number, expireTime: admin.firestore.timestamp };
const { expireSeconds, expireTime } = data;
// This is local variable for storing expirationAtSeconds
let expirationAtSeconds: number | undefined
// Extract expiration time based on provided fields
if(expireSeconds) {
if(expireSeconds > 0) {
expirationAtSeconds = Date.now() / 100 + expireSeconds;
}
} else if (expireTime) {
expirationAtSeconds = expireTime.seconds;
}
// If not time is set for the document we will return
if(expirationAtSeconds == undefined) {
return;
}
const project = json.parse(process.env.FIREBASE_CONFIG!).projectId;
const location = ‘us-central1’;
const queue = ‘my-scheduler’;
const taskClient = new CloudTaskClient();
const queuePath: string = taskClient.queuePath(project, location, queue);
const serviceAccountEmail = “SERVICE_ACCOUNT_EMAIL_HERE”;
const url = `https://${location}-${project}.cloudfunctions.net/schedulerCallback?eventId=${snapshot.id}`;
const payload = { snapshot.id };
const taskName = ‘projects/${project}/locations/${location}/queues/${queue}/tasks’
const task = {
name: `${taskName}/myTask-${snapshot.id}-${expireSeconds}`,
httpRequest: {
httpMethod: ‘POST’,
url: url,
body: Buffer.from(JSON.stringify(payload)).toString(‘base64’),
headers: { ‘Content-Type’: ‘application/json’ }
},
oidcToken: {
serviceAccountEmail,
audience: “https://${location}-${project}.cloudfunctions.net/schedulerCallback”
},
scheduleTime: {
seconds: expirationAtSeconds
}
}
await tasksClient.createTask({ parent: queuePath, task })
});
export const schedulerCallback = functions.https.onRequest(async (req, res) => {
const project = json.parse(process.env.FIREBASE_CONFIG!).projectId;
const location = ‘us-central1’;
const eventId = req.query.eventId as string;
// access the headers > authorization of the request
const authorizationHeader = req.headers.authorization;
// check if authorization header is not null
if(!authorizationHeader) {
res.status(401).send(“unauthorized token”);
return;
}
// if authorizationHeader is not null access the token
const token = authorizationHeader.split(‘ ’)[1];
// verify ID token
try {
await verifyIdToken(token, location, project);
} catch (error) {
console.log(error);
res.status(401).send(“Unauthorized token”);
return;
}
// delete document
try {
await admin.firestore().collection(“events”).doc(eventId).delete();
} catch(e) {
console.log(e);
res.status(500).send(e);
}
});
async function verifyIdToken(token: string, location: any, project: any) {
const client = new OAuth2Client();
const ticket = await client.verifyIdToken({
idToken: token,
audience: “https://${location}-${project}.cloudfunctions.net/schedulerCallback”,
});
return ticket.getPayload();
}
export const onUpdateEventCancel functions.firestore.document(“/events/{eventId}”).onUpdate(async change => {
const eventBeforeUpdate = change.before.data();
const eventAfterUpdate = change.after.data();
// check if event is canceled
if(eventBeforeUpdate.expirationStatus !== eventAfterUpdate.eventAfterUpdate && eventAfterUpdate.expirationStatus === ‘canceled’) {
const project = json.parse(process.env.FIREBASE_CONFIG!).projectId;
const location = ‘us-central1’;
const queue = ‘my-scheduler’;
const taskClient = new CloudTasksClient();
// task details
const eventId = eventAfterUpdate.eventId;
const expireSeconds = eventAfterUpdate.expireSeconds;
// taskName
const taskName = ‘projects/${project}/locations/${location}/queues/${queue}/tasks/myTask-${eventId}-${expireSeconds}’;
await taskClient.deleteTask({ name: taskName });
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment