As two of you know, SuperDuper! has provided an AppleScript interface for some time. We’ve used it to provide the rudimentary scheduling in the v1.x series, and we’ve enhanced as necessary to improve the experience in v2.0.
But, one rather tricky thing fell out during the process: users can (and will) schedule any number of backups in ways that might overlap, or even start them at exactly the same time. And, given the nature of a multi-processor machine, and the fact that each “scheduled job” is an AppleScript external to SuperDuper! that has no knowledge of the other scripts around it, there had to be a way to serialize execution or the scripts would all interfere with each other.
In the v1.x series, we’d put a rudimentary system in place: the script can ask about the current status about SuperDuper! and—if SuperDuper! is busy running another copy, it’ll say just that, and the script just waits until it’s done. This was mostly done to prevent the script from “grabbing” the interface away from a user who’s actively using SuperDuper!.
But, with v2.0, it’s trivial to schedule two copy jobs for the same time, and with the old technique both could be told that SuperDuper! was, indeed, idle. And then, both would try to run at the same time. Clearly, it’s unreasonable to ask users to schedule their own backups in a way that would take this into account: we had to handle it internally.
Of course, another way to handle this is to break SuperDuper! into a true background engine, and have the UI and scripts all “drive” this process (or processes). But, beyond breaking existing scripts, doing so required enough reengineering to push it well beyond the scope of this particular release, much as it would have been cool. Gotta ship sometime, you know?
So. Bruce and I talked about this for a while, and Bruce came up with the idea of just changing the status into a queue. The first process who asked for status is at the front, and only the guy at the front gets the real status at any given time: every other script always gets “busy” until they move to the front of the queue.
Nice, simple solution and—apart from various tricky bits that always plague any solution—it seemed to do the trick.
Which led to another problem. To try to match user expectations, the scheduled jobs try to leave SuperDuper! in the same state it was in when they started. So, if SuperDuper! is running, we leave it running; if not, we quit when we’re done.
The scripts are responsible for this state preservation. And, once again, when launching at the same time, on fast systems both would see SuperDuper! as not running, and would take responsibility for quitting. To avoid quitting the application out from under the others, each would be waiting for the other script to finish… and then, due to the deadlock, SuperDuper! wouldn’t ever quit.
Great.
More discussion, and another simple solution: the quit command basically waits until the queue is empty, and all external processes are done, before it does its thing. And this simplifies the scripts, too, because they just don’t have to worry about it.
And, all without changing the script dictionary… not too bad!
So, we’re sweating the details here. Or trying to.
21 Oct 2005 at 09:57 am | #
Nice job and rather elegant if I may say so. It strikes me that this is a neat OOP-type approach, where the implementation of how the Quit action works is hidden from those processes calling it. Sounds sensible and much easier to code and maintain.
Thanks for these updates on the progress of version 2. I don’t know what I would do without SuperDuper! now - it really is the only app that I have tried that I managed to stick with and keep a regular backup/mirror of my system.
21 Oct 2005 at 10:31 am | #
Glad to hear it, Steve! And v2.0 does make it easier than ever to stick with your backup program…