I found the external_exception confusing at first.
What's going on - cleanup gets called only when Goal is 'done' - has exited with no more choice points, or in some other way is 'over' and will not be backtracked into.
?- setup_call_catcher_cleanup(true, ((X=1;X=2), writeln(X)), C, writeln(C)). 1 X = 1 ; <waits for user> 2 exit X = 2, C = exit.