Skip to content

#167 delete files in S3 when deleted in editor #222

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from

Conversation

PaliwalSparsh
Copy link

@PaliwalSparsh PaliwalSparsh commented Dec 9, 2016

Thanks for the help. Please can you review this.

},
};
let del = client.deleteObjects(params);
del.on('end', function() {
Copy link
Author

@PaliwalSparsh PaliwalSparsh Dec 9, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please can you tell what to do on successful deletion?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What you want to do here is add a second parameter to deleteObjectFromS3, that is a callback function, i.e. export function deleteObjectFromS3(url, callback) { .... Then, here, you call that callback.

For functions that use deleteObjectFromS3, you would use it like this:

deleteObjectFromS3(url, function() {
  //code here that you want to get executed after file is deleted from S3
});


export function deleteProject(req, res) {
// Deleting project files form S3
Project.findById(req.params.project_id, (err, project) => {
Copy link
Author

@PaliwalSparsh PaliwalSparsh Dec 9, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a better way to do this because when retrieving data and removing projects asynchronously. Project would have got removed already before retrieving. Thus i tried to run it synchronously.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left a thorough answer for this in another comment, but the short answer is callbacks 😄

if (err) {
return res.status(404).send({ message: 'Project with that id does not exist' });
function deleteFilesFromS3(files) {
files.forEach(file => {
Copy link
Member

@catarak catarak Dec 9, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here, you might want to use the library async which is already included in this project. It is used for handing lots of callback functions. Specifically, I think it would make sense to use async.each. Then, you can add another parameter to this function which is a callback, which gets called when all of the files have been deleted from S3.

@PaliwalSparsh
Copy link
Author

@catarak Made all the required changes. I never had used async it was really awesome. Thanks 😄, made my day.

if (err) {
return res.status(404).send({ message: 'Project with that id does not exist' });
function deleteFilesFromS3(files, callback) {
each(files, (file, callback) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rename callback here to fileCallback for the sake of clarity.

function deleteFilesFromS3(files, callback) {
each(files, (file, callback) => {
if (!(file.url === undefined)) {
deleteObjectFromS3(file.url, () => {});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The callback setup here is not quite right! This should be

deleteObjectFromS3(file.url, fileCallback);

And then line 73 is extraneous and should be removed.

@@ -39,6 +40,10 @@ function getAllDescendantIds(files, nodeId) {

function deleteMany(files, ids) {
ids.forEach(id => {
// Delete file from S3 bucket
if (!(files.id(id).url === undefined)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is slightly more clear as

if (files.id(id).url !== undefined) {

// Delete file from S3 bucket
if (!(files.id(id).url === undefined)) {
deleteObjectFromS3(files.id(id).url);
}
files.id(id).remove();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be within the deleteObjectFromS3 callback? will this cause an issue where the API returns but the files are still be deleted from S3 and then they don't get deleted properly?

@PaliwalSparsh
Copy link
Author

PaliwalSparsh commented Dec 9, 2016

@catarak I am really really sorry I pushed some more changes while you were reviewing didn't knew about it. Actually before it was deleting all files using different requests, now i made it to delete all files in one request. Though the changes you suggested still make sense I will try to get them right.

files.id(id).remove();
callback();
}, (err) => {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3rd parameter (err) => {} is called when async for all the element gets completed or hits an error. Thus, upon completion ie getting urlList I had given the list to deleteObjectsFromS3.

return res.json({ success: true });
callback();
}, (err) => {
fileCallback();
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here this
deleteObjectsFromS3(s3ObjectUrlList, fileCallback);
was not used because if the project had many files on S3, only when all these files got deleted from S3 we get the fileCallback running. Thus, when we click on the delete button in front of a project in the "My sketches" dialogue box, the project remains there for a while and after few seconds it would disappear, when fileCallback gets executed upon getting response from S3 that files have been deleted.

Also once we get list of URL we need to delete from S3 we don't need anything else. We can safely delete files locally and S3 delete operation can be done after that.

@PaliwalSparsh
Copy link
Author

I have made the changes you suggested. Please can you review the PR again. Thankyou.

@catarak
Copy link
Member

catarak commented Dec 12, 2016

A couple things I noticed:

  1. If a project has never been saved, or a file has been uploaded and the project has not been saved since the file has been uploaded, the file will not get deleted from S3. I guess this will either have to happen on the front-end, or an API request to the web editor API will have to be made to delete the file.
  2. I'm actually not able to get this working, but I think it's a configuration option on my end. I think it has to do with the region in the URL? I'll look into it, but it may mean we have to include the region in the .env file.

screen shot 2016-12-12 at 12 10 50 pm

EDIT: I was able to fix the second bug by adding a region to s3Options in s3Operations.js. So I guess this should be added to the .env file.

@catarak
Copy link
Member

catarak commented Dec 15, 2016

I also thought of another bug that this causes:
If a user creates a project, uploads a file to S3 for that project, then duplicates that project, then two projects reference the same S3 file via its URL. As of right now, the file is not duplicated on S3. Then, if one of those projects is deleted, then the other project will be broken because the file it references will be deleted.

So I think the solution to this is to copy the files on S3 when a user duplicates a project. Definitely not the most $$$ efficient, but we'll put a limit to how much a user can upload which will help.

But also you don't need to fix this for this PR, it's just something that should happen side by side with this PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants