That Should not Occur – UnreachableException in .NET 7
At Abbot, we’re constructing SlackOps for Buyer Success groups. We work together with loads of exterior programs. These exterior programs outline their API and inform us what to anticipate, but when we’re not cautious, that would simply change out from underneath us and trigger a bunch of issues. Even when we restrict ourselves to our personal elements, there are all kinds of undefined behaviors that would occur if element X does one thing element Y doesn’t anticipate. There are such a lot of “unattainable” eventualities that it appears apparent that sometime one in every of them will all of a sudden turn into potential.
So, diligent engineers that we’re, we do our greatest to be ready for the surprising. We verify for these edge circumstances and attempt to fail quick and early. Even higher, we wish our system to have the ability to shortly establish when one in every of these “unattainable” issues occurs and notify us so we will repair the problem with minimal impression to our clients. Fortuitously, .NET 7 provides a brand new sort to assist us out right here: UnreachableException.
Enums and Switches
Right here’s a concrete instance. I’ve written extra “change” statements over enum choices than I might depend. However in C#, enums are “open” (for now), which implies any integer might be solid into any enum sort. It won’t match one of many outlined choices in my enum, but it surely’s nonetheless legitimate conduct. So in fact, each a type of change statements has a “default” case which throws if an surprising worth happens. In .NET 7, we now throw an UnreachableException. For instance, right here’s some code that gives a pleasant standing message for a Slack dialog we’re monitoring, relying on its present state:
There on the backside, you may see the “default” case the place we’re throwing an UnreachableException. There’s no want for a message since we’ll get a stack hint with the exception and we’ll know precisely why it’s occurring primarily based on the situation within the code (assuming we will monitor that down; extra on that later).
Null Checking
One other widespread sample is null checking. After we’re coping with all these exterior programs, now we have various eventualities the place the API of an exterior service is evident {that a} worth ought to by no means be null, however we’re not assured sufficient to mark it as non-nullable (we use nullable reference varieties closely). For instance, this code processes incoming occasions from Slack and shops them in our personal knowledge construction:
On the backside, we’re assigning the “envelope.TeamId” to “SlackEvent.TeamId”. Nicely, “envelope” is an object deserialized from Slack’s payload, and never all messages present a “TeamId”, so we outlined it as “string?” to make sure we had null checks in place. However at this level in our code, we know it’s a message that ought to have the TeamId property set. The “SlackEvent.TeamId” property is non-nullable, as a result of we completely know we’d like a TeamId by the point we’ve created it. We might simply write “TeamId = envelope.TeamId!” to bypass the null checking solely. In all anticipated circumstances, that may work high quality. The worth “shouldn’t ever be null” so we’re good, proper? Nicely, we’re not fairly so trusting. That’s the place the “Require” extension technique comes into play:
Through the use of “[CallerArgumentExpression]” on the “expression” parameter, the C# compiler will robotically fill that parameter in with a string illustration of the expression that was used to specify the “o” parameter. So in “envelope.TeamId.Require()”, if the TeamId is null, the exception message will likely be “The expression ‘envelope.TeamId’ shouldn’t be null.”.
Usually, I’m not a giant fan of defining extension strategies so broadly. And I’m additionally not usually a fan of extension strategies that may take ‘null’ for his or her ‘this’ parameter (in spite of everything, common strategies can’t). However this one is simply so helpful that it appears value it.
Different Sudden Behaviors
There are a myriad of different surprising behaviors in our system, as with every system. For instance, after we show a dialog to a Slack person, Slack validates that the fields we marked as required are literally stuffed in. For instance, when a person desires to create a HubSpot Ticket from a Slack dialog, the “Topic” discipline is required:
When Slack informs us of a profitable type submission, we will assume that required fields are certainly current. However nonetheless… suppose the worth is lacking for some cause? Higher to only verify (that is really from a barely completely different instance, however the gist is identical):
Sounding the Alarms
Okay, so we’ve been placing UnreachableException all through our code to detect these circumstances the place one thing that “shouldn’t ever occur” really occurred. Nice. Now we have to detect and alert on these conditions so we will discover them and monitor them down. I’ll skip to the top first and present you what the outcome appears to be like like:
This alert will get posted to a Slack channel if any of a set of “very dangerous” exceptions get thrown in manufacturing. That permits us to react and repair the issue shortly, earlier than too many purchasers are affected.
We use Azure Software Insights to gather our logs and exceptions. Any time an exception bubbles as much as the highest of a request stack, it will get logged to App Insights. Then, now we have an Azure Alert set as much as verify for exceptions at a daily interval:
We’re checking for a number of sorts of “that shouldn’t occur” exceptions, however you may see “System.Diagnostics.UnreachableException” tucked away in there. The total question is one thing like this:
The alert is configured to publish to an HTTP Triggered Skill we created utilizing Abbot’s ChatOps platform, which then posts the message you noticed above to Slack. In fact, utilizing Abbot to watch Abbot is cool and works more often than not, however doesn’t actually assist us if Abbot is down! So, we additionally configured the Azure Alert to ship an e mail out to our engineering staff.
After we need to examine the exceptions, we will go to App Insights and run the identical question the alert runs:
Digging into these outcomes we will see a stack hint (the road numbers are reduce off, however they are there!) and, simply as critically, now we have a GitCommitId worth that tells us the commit from which the app was constructed. We use Nerdbank.GitVersioning to embed the commit hash in our meeting, after which proper because the app begins, we begin a logger scope with the commit hash so each message we log has that property hooked up:
Conclusion
Sudden conduct is the shadow that lurks in each manufacturing utility. It’s scary! Fortuitously, .NET offers some instruments to assist convey mild to these areas, and Azure’s monitoring platform offers us a approach to sound the alarm each time one in every of “That Shouldn’t Occur” occasions really occurs. Prior to now, I’ve simply kinda mashed in no matter exception sort appeared related to the state of affairs (ArgumentException? InvalidOperationException?), however with UnreachableException, now we have a kind designed precisely for issues that ought to by no means occur.
Quick-moving groups use Slack for buyer help. With automated insights, reminders, integrations, and extra, Abbot makes utilizing Slack for customer support simple. Serious about studying extra? Electronic mail us at hello@ab.bot!