When a notebook crashes all the work I was doing is lost - I'd like to ameliorate this situation!

Is there a way to decorate a symbol so that it is saved to disk whenever it changes, or after a certain repeating time interval?

I find myself wasting lots of time manually performing such a disk-caching mechanisms for important variables and functions (usually by appending to global lists and saving new .mx files with DumpSave by hand). Here's what I'd like to call it:

CrashProtect[_Symbol] := (* ... *)
CrashProtect[_Function] := (* ... *)

I realize there is overhead involved but typically only a few symbols or functions are critical and would need this sort of treatment.

Note: MMA 10.3 kernel is more stable than ever! Sadly the front-end crashes for me still very frequently - especially when dealing with dynamics or large/multiple notebooks.

  • 5
    $\begingroup$ You have Mma 10.3? $\endgroup$ – Szabolcs Aug 21 '15 at 19:40
  • 1
    $\begingroup$ $Post comes to mind. $\endgroup$ – Sjoerd C. de Vries Aug 21 '15 at 20:30
  • $\begingroup$ Related, see especially the "File-backed In-memory Approach" section. $\endgroup$ – Alexey Popkov Aug 21 '15 at 21:26
  • 3
    $\begingroup$ You might want to check out LocalSymbol and LocalObject. $\endgroup$ – Stefan R Aug 21 '15 at 22:15
  • $\begingroup$ Also PersistentValue, if you have 11.2. Allows you to save persistently in a Notebook. $\endgroup$ – b3m2a1 Jan 2 '18 at 16:31

If you can keep a cell on screen, Dynamic can do it.

Perhaps not the prettiest of methods, but here's one possible approach:

autobackup[x_, f_] := Dynamic[Put[x, f]; "Magic cell - used for backup.", 
    UpdateInterval -> 30, Initialization :> (x = Get[f];)];

Takes a variable x and file path f, and creates a Dynamic cell that automatically saves the value of x to disk at f whenever x changes (specifically, when those changes trigger Dynamic cells) or every 30 seconds. It then reloads those values from the disk whenever the Dynamic cells are initialized, providing continuity across kernel sessions.

Will not work with functions specified in the standard SetDelayed (:=) syntax, but should work with functions specified as f=Function[{x},x+...], which may be useful in some projects.

This does require keeping the magic cell around though, since that's what the Dynamic is attached to, and thus the output should not be suppressed with ;.

Reloading the values after a kernel crash/quit may require re-running the autoupdate input cells.

Otherwise, you can schedule a repeating task to save at a constant time interval.

autobackup[x_, f_, t_] := (If[FileExistsQ[f], x = Get[f]]; 
    RunScheduledTask[Put[ReleaseHold[x], f], t]);
SetAttributes[autobackup, HoldFirst];

This takes a variable x, file path f, and time between saves t, and creates a scheduled task which will attempt to save x to f every t seconds.

If you want dynamic updating without the magic cells, you can attach the Dynamic to the notebook.

autobackup[xl_List, f_] :=
SetOptions[EvaluationNotebook[], NotebookDynamicExpression ->
        If[nbdeinit === True, Put[Evaluate[xl], f], 
            If[FileExistsQ[f], xl = Get[f]];
            nbdeinit = True],
        TrackedSymbols :> xl]];
SetAttributes[autobackup, HoldFirst];

This takes a list of variables xl and a file name f, and sets up a NotebookDynamicExpression which will update so long as the notebook is open. This does require the use of a dummy initalization variable, because apparently the Initialization rule for Dynamic won't trigger for NotebookDynamicExpression. Also note that this doesn't appear to recover gracefully from kernel crashes unless the notebook is reopened, though it won't break anything either (the Dynamic is simply not evaluated at all, it seems).

  • 1
    $\begingroup$ This will work only while the Dynamic cell is displayed on the screen... $\endgroup$ – Alexey Popkov Jan 2 '18 at 7:11
  • $\begingroup$ Is that so? That can be somewhat mitigated by having it in a separate notebook on another screen, rendered; but that becomes very convoluted quickly. I'll take a look at alternatives. $\endgroup$ – eyorble Jan 2 '18 at 7:12
  • $\begingroup$ @eyorble This looks like a wonderful idea. How can this modified so that at a timed interval the entire contents of EvaluationNotebook[] (the notebook being worked on) is dumped into another file (i.e. mynotebookBACKUP.nb) completely replacing everything in there if not empty without affecting the focus of the directory structure when doing a manual File->Save of mynoteook.nb? I could see using something like this on half hour intervals while using manual saves more frequently when working on risky code. $\endgroup$ – Jules Manson Sep 16 '20 at 9:32
  • $\begingroup$ @JulesManson Seems like a different fundamental question to me, but you can Export[filename,EvaluationNotebook[]] to save the current notebook. Combining that with the second code in my answer above in place of the Put[...] would likely work for your needs. You likely want to include a timestamp in the filename so that you can rollback to any version you need to in the event of a crash. .nb files aren't usually extremely big, so disk space probably isn't an issue. Like normal saves though, won't save any additional variable states though. $\endgroup$ – eyorble Sep 16 '20 at 14:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.