derekantrican / GAS-ICS-Sync

A Google Apps Script for syncing ICS/ICAL files faster than the current Google Calendar speed
GNU General Public License v3.0
1.5k stars 192 forks source link

Avoiding getting stuck when failing due to uncaught exception #435

Open Sp3EdeR opened 4 months ago

Sp3EdeR commented 4 months ago

When an exception propagated outside of the script, the script failed to run for a while, exiting with the message:

Another iteration is currently running! Exiting...

This avoids such a case by resetting the last run time in case of an uncaught exception

derekantrican commented 4 months ago

Can you clarify why this is needed? What exception are you seeing?

At the very start (just below the Another iteration... log message) is where the LastRun prop is set:

PropertiesService.getUserProperties().setProperty('LastRun', new Date().getTime());

There shouldn't need to be any resetting of this property because it's just a timestamp. The script will run the next iteration when that timestamp is "too old".

Sp3EdeR commented 4 months ago

Hello @derekantrican, The timeout is currently set to 6 minutes. This can cause issues when the synchronization frequency is set to a more frequent time than this, by causing instantly exiting runs within the log. Furthermore, when testing or debugging a modification, having to wait 6 minutes between failing runs seems inefficient. With this modification, the script can be deterministically rerun right away, regardless of whether it succeeded or failed due to an exception.

derekantrican commented 4 months ago

It is 6 minutes right now because that is the maximum execution time allowed by Google Apps Script: https://developers.google.com/apps-script/guides/services/quotas#current_limitations

We don't usually encourage syncing calendars faster than 5 minutes (I usually even encourage 15 minutes as this is still MUCH faster than Google Calendar's current speeds of many hours),

EDIT: removing my suggestion. I think I'm going to classify this PR suggestion in one of two buckets: 1) if you're getting some sort of exception, we should investigate the exception and see if we can fix it or 2) if your calendar is taking more time to sync than your howFrequent setting, then that is user error and you need to adjust your howFrequent setting to longer.

As to the point of "when testing or debugging...", I think if you are frequently testing changes with the script, you can figure out how to comment out this if block while testing.

Sp3EdeR commented 4 months ago

Oh, I already fixed my issues. There is a branch in my fork that does some specialized work for my use-case. My primary problem was that Facebook randomly sends a reply that is HTTP 200, but does not parse as a valid ICS. In this case, the synchronization removed deleted all events from the affected calendar, which was a big problem for the service I based on the affected calendar. I did not go into this deep enough to try to log and catch what they send when it is an invalid file. I just modified the code so that invalid ICS files interrupt the sync run (since in my use-case, there is only one calendar to be synced anyway). This initially went through as an uncaught exception, for which I added specific handling in the callWithBackoff function, since essentially that was the behaviour I needed here. But before then, this behaviour caused one extra unnecessary testing round for me, so I thought I'd contribute it back, as it could be helpful.

As for commenting that code while debugging... I didn't really want to remove this check in a "live" deployment scenario, and the intermittentness of the issue + this behaviour made it a bit more annoying to sort out than I felt was necessary. No biggie though.

I understand the time recommendation, and it makes sense in most cases of course. But since the original code resets the LastRun on successful completion, this feature doesn't do anything about that (nor should it, I suppose). The only thing that this try..catch does is that it makes the fail-behaviour the same as the current success-behaviour is.

darylmonge commented 4 months ago

I had the same problem, with our cycling club calendar feed (strautomator.com) throwing a 500 error that was not caught by callWithBackoff and deleting all our (future) calendar entries. This was especially nasty because we have a zapier.com task that emails deleted (cancelled) ride events.

Oh, I already fixed my issues. There is a branch in my fork that does some specialized work for my use-case. My primary problem was that Facebook randomly sends a reply that is HTTP 200, but does not parse as a valid ICS. In this case, the synchronization removed deleted all events from the affected calendar, which was a big problem for the service I based on the affected calendar. I did not go into this deep enough to try to log and catch what they send when it is an invalid file. I just modified the code so that invalid ICS files interrupt the sync run (since in my use-case, there is only one calendar to be synced anyway). This initially went through as an uncaught exception, for which I added specific handling in the callWithBackoff function, since essentially that was the behaviour I needed here. But before then, this behaviour caused one extra unnecessary testing round for me, so I thought I'd contribute it back, as it could be helpful.

As for commenting that code while debugging... I didn't really want to remove this check in a "live" deployment scenario, and the intermittentness of the issue + this behaviour made it a bit more annoying to sort out than I felt was necessary. No biggie though.

I understand the time recommendation, and it makes sense in most cases of course. But since the original code resets the LastRun on successful completion, this feature doesn't do anything about that (nor should it, I suppose). The only thing that this try..catch does is that it makes the fail-behaviour the same as the current success-behaviour is.

Sp3EdeR commented 4 months ago

I had the same problem, with our cycling club calendar feed (strautomator.com) throwing a 500 error that was not caught by callWithBackoff and deleting all our (future) calendar entries. This was especially nasty because we have a zapier.com task that emails deleted (cancelled) ride events.

If your issue persists, my customization for this is here: https://github.com/Sp3EdeR/GAS-Facebook-Event-Sync/commit/5b3081bf6720645ebd8a92db1a7ae66acba2510b. Disclaimer, this does not handle the case when maxtries is reached, and callWithBackoff gives up. If the issue is that bad, it may be useful to throw an exception in the callWithBackoff ( tries > maxRetries) condition to fully fail the script run. This is off-topic for this PR though.