Otherwise, some situations simply don't warrant a full shutdown, and it might be okay to run the application in degraded mode.
Otherwise, some situations simply don't warrant a full shutdown, and it might be okay to run the application in degraded mode.
Yes but what is worse is silently corrupting the data or the state because of running in buggy state.
If you don't know what the state of your app is, how do you prevent data corruption or logical errors in further execution?
I'd have to think long and hard about each individual case of running in degraded mode though. Sometimes that's appropriate: an OS kernel should keep going if someone unplugs a keyboard. Other times it's not: it may be better for a database to fail than to return the wrong set of rows because of a storage error.
This is part of why something like Rust is usable at all; in the real world a lot of logic has straightforward, linear lifecycles. To the extent that it doesn't, you can push the long-lived state into something like an external database, and now your application has straightforward lifecycles again where the goal of a task is to produce commands to manipulate the database and then exit.
Even worse, you might be in an unknown state because someone is trying to exploit a vulnerability.
There are a lot of patterns for this. Its perfectly fine and often desirable to scope the blast radius of an error short of crashing everything.
OSes shouldn't crash because a process had an error. Servers shouldn't crash because a request had an error. Missing textures shouldn't crash your game. Cars shouldn't crash because the infotainment system had an error.
How often do you see code written this way?
In most real-world application programming languages (i.e. not C and C++), you don't really have the ability to access arbitrary memory, so if you know you never gave task B a reference to task A or its resources, then you know task B couldn't possibly interfere with task A. It's not dissimilar to two processes being unable to interfere with each other when they have different logical address spaces. If B does something odd, you just abort it and continue with A. In something like an application server, it is completely normal for requests to have minimal shared state internal to the application (e.g. a connection pool might be the only shared object, and has a relatively small boundary that doesn't allow its clients to directly manipulate its own internals).