Can I write files during the app.cancelClose event

I have a Mac/Windows desktop app, storing and displaying data in a database.

Users have the option to do automatic backups of that data to an external drive, done by simply copying the database to the users preferred drive everytime the app quits. I put that code into the app.CancelClose event. This happened silently - there is no messagebox or option for the user to cancel quitting.

Some users are reporting that if they choose a cloud-based drive to store their backups, such as Dropbox/iCloud/OpenDrive, the automatic backup when the app quits does not happen.

My question: Does all the code in the CancelCode event get executed before the app quits? Why is my backup during the app.cancelClose event not working on cloud-based drives? Is writing to a cloud drive relatively slow, and does the app quit before all the code in the CancelClose event is finished?

Does all the code in the CancelCode event get executed before the app quits?
Yes

Is writing to a cloud drive relatively slow,
Yes. And in my experience, unreliable.

does the app quit before all the code in the CancelClose event is finished?

it shouldnt.
What form does your backup take? Database? Binary/text/xml?
I can imagine a race condition where the save appears complete but the database object is nil before a commit goes through.
If you save in a temp folder, then copy the file bodily to the final destination, you may have better luck, because your cloud service only ever sees a fully completed file in that instance - it hasn’t had a chance to start uploading before you finish writing. (That may be a naive description of what happens, but it ‘explains’ a lot of the carp I have experienced in the past)

Yes, CancelClose must finish before the app quits.

If you can reproduce a circumstance where it doesn’t, I would call that a bug.

It’s a simple SQLite database. The main database is stored on the users drive in SepcialFolder.ApplicationData.

I used a simple FolderItem.CopyTo to copy the entire database to the user’s preferred backup drive for backup purposes. The code for that is in the app.CancelClose event. So the users main data is always preserved, but a backup is made elsewhere every time the user quits the app.

I have had 2 users complain their hard drive failed, and lost their main data, and when they went to get their automatic backups from their drive, there was one copy from months ago, but never updated.

The cloud drives (Dropbox/iCloud/onedrive) usually have a virtual directory on the users drive that should get written quickly, and uploaded to the cloud afterwards, so I’m really not sure why their cloud backups don’t get written.

I can’t reproduce it on my machine, tested on Dropbox, iCloud and OneDrive, but I have had 2 computer-savvy users say they lost data because the backup never got updated to their cloud drives.

When I save to any of these cloud drives, the data gets written to the local drive directory, and uploaded a few seconds later (depending on the size).

So I’m at a loss to explain it. If CancelClose must finish before the app closes, the file should be copied to their drive, even if it doesn’t get fully uploaded before the app closes.

SQLite can use more than one file, it can also use WAL and SHM files in addition to the main database file. Possibly these files aren’t getting copied, leaving the database in a bad state? See Write-Ahead Logging

You can disable WAL mode if needed.

1 Like

The backup SQLite file doesn’t get updated on app quitting, the timestamp doesn’t change. No extra files appear.

So brainstorming: is there any way (apart from power failure) that a user can quit an app WITHOUT the app.CancelClose event being called? I have App.AutoQuit set to True.

Another theory - what if they literally never quit the app? macOS is pretty stable these days, so maybe they left the app running for 3 months, and then when their hard drive died their computer also crashed.

If this is the case, the solution would be to do the auto-backup feature on some sort of timer.

interesting thought …

A force-quit would bypass that event.

I use a thread to effect backups and other housekeeping actions, which runs once an hour.

Take care if using threads. They will be terminated if the app is asked to quit, even if the thread has not completed. I used the CancelClose event to ask the required "do you want to save questions and then cancelled the quit. Once the threads were fully executed and the data saved I then triggered a second quit without asking questions and allow it to proceed right away.

1 Like

You can write to tmp folder than move the file to the network drive after the writing. This is pretty normal to do for network drives.

I think Dropbox, iCloud and OneDrive essentially do that automatically. They write to a local drive directory and the contents get uploaded later.

Yep, but I doubt my users were force-quitting every time.

I would not make that assumption. I had a customer once that kept Microsoft Word running all the time and when he needed a new document, he just added a new page. When he lost power one day, he couldn’t understand why he lost all of his documents… because he never bothered to save…

6 Likes

That shouldn’t be happening.

There was a regression in the framework where threads got killed before App.Close was called but that was fixed in 2018r4.

It was described as normal. The window cancel close allows the app to close, but started a thread to perform the save. Once each window had completed that process it allowed app.close to happen, killing the threads.

Well, under those circs, it would. I had a Termination thread for a while in my app (no longer needed now), and it waited until another thread, which was saving data from an HTMLViewer, reported it had completed. Then the Termination thread issued the final Quit.

It’s only a matter of thinking about possible race conditions and concocting the appropriate interlocks.