0

I am still getting the hang of Firebase and Cloud functions, but here is what I'm trying to figure out.

The current setup

My app has a cloud function that will take a PDF that has been uploaded into a storage bucket and convert it into PNG. It doesn't destroy the original PDF, so I am left with both files.

The URL for the newly created PNG is then attached to a property on one of our documents in Firestore.

What I am trying to accomplish

I want to be able to upload a new PDF to use as a replacement image. I think I am running into a race condition where the cloud function hasn't finished executing by the time I am trying to call updateDoc() with the new PNG.

On the client side, I have the storageRef returned from the upload method:

uploadFunction(...).then((snapshot) => {
     return snapshot.ref
}

I'm saving the result of this function to a variable, and I am trying to pass that into the update method that will adjust the property on my document in Firestore:

const storageRef = await functionThatUploadsPDF(file);

updateDocumentInFirestore(storageRef);

Within updateDocumentInFirestore, I'm trying to navigate to the new reference that should exist once the cloud function has finished, get a download URL, and update that property on my document:

const newImageRef = ref(storageRef.parent, "generatedImage.png");

const newDownloadURL = getDownloadURL(newImageRef).then((url) => {
     updateDoc(documentRef, backgroundImage: url);
});

However, I am getting the following error - I believe due to the cloud function having not finished yet:

Firebase Storage: Object 'storage-bucket/generatedImage.png' does not exist. (storage/object-not-found)

My thoughts on potential solutions

  1. I could try to poll the storage for the existence of generatedImage.png until the getDownloadURL call returns an actual URL, but I worry about the amount of calls this would yield.

  2. If there is a way for the cloud function to send a message to let me know that the conversion is finished, I can send a call once for the download URL after receiving said message. However, I can't figure out how to accomplish this.

Efforts so far

I have been pursuing course 1. So far, but have not met any success yet. Scouring through Firebase documentation, I haven't been able to find any supporting resources on how to accomplish 1 or 2. Does anyone have any suggestions - either on my planned courses of action, or a new option that I haven't considered?

Ken White
  • 123,280
  • 14
  • 225
  • 444
  • Did you have a look to Cloud Workflow? – guillaume blaquiere Jan 13 '23 at 11:26
  • 1
    @guillaumeblaquiere I hadn’t known that Cloud Workflows existed before seeing your comment. I was hoping to find a solution within our existing code base, but I will also take a look at this as it may help what I’m trying to do. Thanks – DJLionheart Jan 13 '23 at 15:26

1 Answers1

1

You can use this onFinalize trigger to send a message or update a document in Firestore to indicate that the function has finished running. This trigger is triggered whenever a file is created or updated.

onFinalize Sent when a new object (or a new generation of an existing object) is successfully created in the bucket. This includes copying or rewriting an existing object. A failed upload does not trigger this event.

you can also create a promise that resolves when the downloadURL is not null, and use that promise in your updateDocumentInFirestore function. This way, the updateDoc function will only be called once the downloadURL is available.

Additionally, as was mentioned in the comments, you can consider cloud workflow.The exact implementation will depend on your specific use case

You can also check these similar cases

Firebase Storage: Object does not exist

Error: storage/object-not-found when trying to upload large image file

Firebase Storage Put could not get object

Sathi Aiswarya
  • 2,068
  • 2
  • 11