Here are a few ideas:
1. Create a filesystem snapshot before the upgrade that you can roll back to if the upgrade fails.
2. (Something I did for a product at a previous employer) - install every update in a new directory, then upon (re)launch of the app, find the newest update dir and calculate a checksum for all files in it and compare to a csum file in the dir - if no match, delete the dir and try the next - continue until success. Then launch app from newest successful dir (which may then retry downloading and applying updates). Requires a small "find best dir and launch app wrapper" that you really don't want to screw up during an update, but other than that seemed to work well.
3. Copy all files before changing them and then move them back if anything fails.
4. Make your app dir a git repo.