mirror of
https://github.com/goldbergyoni/nodebestpractices.git
synced 2025-10-27 19:17:13 +08:00
1
This commit is contained in:
@ -1,30 +1,29 @@
|
||||
# Title here
|
||||
# Discover errors and downtime using APM products
|
||||
|
||||
|
||||
### One Paragraph Explainer
|
||||
|
||||
Text
|
||||
Exception != Error. Traditional error handling assumes the existence of Exception but application errors might come in the form of slow code paths, API downtime, lack of computational resources and more. This is where APM products come handy as they allow with minimal setup to detect a wide variety of ‘burried’ issues proactively. Among the common features of APM products are – alerting when HTTP API returns errors, detect when API response time drops below some threshold, detection of ‘code smells’, monitor server resources, operational intelligence dashboard with IT metrics and many other useful features. Most vendors offer a free plan.
|
||||
|
||||
### Wikipedia about APM
|
||||
|
||||
In the fields of information technology and systems management, Application Performance Management (APM) is the monitoring and management of performance and availability of software applications. APM strives to detect and diagnose complex application performance problems to maintain an expected level of service. APM is “the translation of IT metrics into business meaning ([i.e.] value)
|
||||
Major products and segments
|
||||
|
||||
### Understanding the APM marketplace
|
||||
|
||||
APM products constitues 3 major segments:
|
||||
|
||||
1. Website or API monitoring – external services that constantly monitor uptime and performance via HTTP requests. Can be setup in few minutes. Following are few selected contenders: Pingdom, Uptime Robot, and New Relic
|
||||
|
||||
2. Code instrumetation – products family which require to embed an agent within the application to benefit feature slow code detection, exceptions statistics, performance monitoring and many more. Following are few selected contenders: New Relic, App Dynamics
|
||||
|
||||
3. Operational intelligence dashboard – these line of products are focused on fasciliatitating the ops team with metrics and curated content that helps to easily stay on top of application peroformance. This is usually involves aggregating multiple sources of information (application logs, DB logs, servers log, etc) and upfront dashboard design work. Following are few selected contenders: Datadog, Splunk
|
||||
|
||||
|
||||
### Code Example – explanation
|
||||
|
||||
```javascript
|
||||
code here
|
||||
```
|
||||
|
||||
### Code Example – another
|
||||
|
||||
```javascript
|
||||
code here
|
||||
```
|
||||
|
||||
### Blog Quote: "Title"
|
||||
From the blog pouchdb.com, ranked 11 for the keywords “Node Promises”
|
||||
|
||||
> …text here
|
||||
|
||||
### Image title
|
||||

|
||||
|
||||
|
||||
### Example: UpTimeRobot.Com – Website monitoring dashboard
|
||||

|
||||
|
||||
### Example: AppDynamic.Com – end to end monitoring combined with code instrumentation
|
||||

|
||||
@ -5,19 +5,6 @@
|
||||
|
||||
REST APIs return results using HTTP code, it’s absolutely required for the API user to be aware not only about the API schema but also about potential errors – the caller may then catch an error and tactfully handle it. For example, your API documentation might state in advanced that HTTP status 409 is returned when the customer name already exist (assuming the API register new users) so the caller can correspondingly render the best UX for the given situation. Swagger is a standard that defines the schema of API documentation with eco-system of tools that allow creating documentation easily online, see prtint screens below
|
||||
|
||||
|
||||
### Code Example – explanation
|
||||
|
||||
```javascript
|
||||
code here
|
||||
```
|
||||
|
||||
### Code Example – another
|
||||
|
||||
```javascript
|
||||
code here
|
||||
```
|
||||
|
||||
### Blog Quote: "You have to tell your callers what errors can happen"
|
||||
From the blog Joyent, ranked 1 for the keywords “Node.JS logging”
|
||||
|
||||
|
||||
@ -1,30 +1,54 @@
|
||||
# Title here
|
||||
# Shut the process gracefully when a stranger comes to town
|
||||
|
||||
|
||||
### One Paragraph Explainer
|
||||
|
||||
Text
|
||||
Somewhere within your code, an error handler object is responsible for deciding how to proceed when an error comes in – if the error is trusted (i.e. operational error, see further explanation within best practice #3) then writing to log file might be enough. Things get hairy if the error is not familiar – this means that some component might be in a fault state and all future requests are subject to failure. For example, assuming a singleton, stateful token issuer service that threw an exception and lost its state – from now it might behave unexpectedly and cause all requests to fail. Under this scenario, kill the process and use a ‘Restarter tool’ (like Forever, PM2, etc) to start with a clean slate.
|
||||
|
||||
|
||||
### Code Example – explanation
|
||||
|
||||
### Code example: deciding whether to crash
|
||||
|
||||
```javascript
|
||||
code here
|
||||
//deciding whether to crash when an uncaught exception arrives
|
||||
//Assuming developers mark known operational errors with error.isOperational=true, read best practice #3
|
||||
process.on('uncaughtException', function(error) {
|
||||
errorManagement.handler.handleError(error);
|
||||
if(!errorManagement.handler.isTrustedError(error))
|
||||
process.exit(1)
|
||||
});
|
||||
|
||||
|
||||
//centralized error handler encapsulates error-handling related logic
|
||||
function errorHandler(){
|
||||
this.handleError = function (error) {
|
||||
return logger.logError(err).then(sendMailToAdminIfCritical).then(saveInOpsQueueIfCritical).then(determineIfOperationalError);
|
||||
}
|
||||
|
||||
this.isTrustedError = function(error)
|
||||
{
|
||||
return error.isOperational;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Code Example – another
|
||||
|
||||
```javascript
|
||||
code here
|
||||
```
|
||||
|
||||
### Blog Quote: "Title"
|
||||
From the blog pouchdb.com, ranked 11 for the keywords “Node Promises”
|
||||
### Blog Quote: "The best way is to crash"
|
||||
FFrom the blog Joyent
|
||||
|
||||
> …text here
|
||||
|
||||
### Image title
|
||||

|
||||
> …The best way to recover from programmer errors is to crash immediately. You should run your programs using a restarter that will automatically restart the program in the event of a crash. With a restarter in place, crashing is the fastest way to restore reliable service in the face of a transient programmer error…
|
||||
|
||||
|
||||
|
||||
### Blog Quote: "There are three schools of thoughts on error handling"
|
||||
From the blog: JS Recipes
|
||||
|
||||
> …There are primarily three schools of thoughts on error handling:
|
||||
1. Let the application crash and restart it.
|
||||
2. Handle all possible errors and never crash.
|
||||
3. Balanced approach between the two
|
||||
|
||||
|
||||
### Blog Quote: "No safe way to leave without creating some undefined brittle state"
|
||||
From Node.JS official documentation
|
||||
|
||||
> …By the very nature of how throw works in JavaScript, there is almost never any way to safely “pick up where you left off”, without leaking references, or creating some other sort of undefined brittle state. The safest way to respond to a thrown error is to shut down the process. Of course, in a normal web server, you might have many connections open, and it is not reasonable to abruptly shut those down because an error was triggered by someone else. The better approach is to send an error response to the request that triggered the error, while letting the others finish in their normal time, and stop listening for new requests in that worker.
|
||||
@ -1,30 +1,37 @@
|
||||
# Title here
|
||||
# Test error flows using your favorite test framework
|
||||
|
||||
|
||||
### One Paragraph Explainer
|
||||
|
||||
Text
|
||||
Testing ‘happy’ paths is no better than testing failures. Good testing code coverage demands to test exceptional paths. Otherwise, there is no trust that exceptions are indeed handled correctly. Every unit testing framework, like Mocha & Chai, has a support for exception testing (code examples below). If you find it tedious to test every inner function and exception – you may settle with testing only REST API HTTP errors.
|
||||
|
||||
|
||||
### Code Example – explanation
|
||||
|
||||
### Code example: ensuring the right exception is thrown using Mocha & Chai
|
||||
|
||||
```javascript
|
||||
code here
|
||||
describe("Facebook chat", () => {
|
||||
it("Notifies on new chat message", () => {
|
||||
var chatService = new chatService();
|
||||
chatService.participants = getDisconnectedParticipants();
|
||||
expect(chatService.sendMessage.bind({message: "Hi"})).to.throw(ConnectionError);
|
||||
});
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
### Code Example – another
|
||||
### Code example: ensuring API returns the right HTTP error code
|
||||
|
||||
```javascript
|
||||
code here
|
||||
```
|
||||
|
||||
### Blog Quote: "Title"
|
||||
From the blog pouchdb.com, ranked 11 for the keywords “Node Promises”
|
||||
|
||||
> …text here
|
||||
|
||||
### Image title
|
||||

|
||||
|
||||
|
||||
it("Creates new Facebook group", function (done) {
|
||||
var invalidGroupInfo = {};
|
||||
httpRequest({method: 'POST', uri: "facebook.com/api/groups", resolveWithFullResponse: true, body: invalidGroupInfo, json: true
|
||||
}).then((response) => {
|
||||
//oh no if we reached here than no exception was thrown
|
||||
}).catch(function (response) {
|
||||
expect(400).to.equal(response.statusCode);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
```
|
||||
@ -1,30 +1,51 @@
|
||||
# Title here
|
||||
# Use a mature logger to increase errors visibility
|
||||
|
||||
|
||||
### One Paragraph Explainer
|
||||
|
||||
Text
|
||||
We all loovve console.log but obviously a reputable and persisted Logger like Winston, Bunyan or L4JS is mandatory for serious projects. A set of practices and tools will help to reason about errors much quicker – (1) log frequently using different levels (debug, info, error), (2) when logging, provide contextual information as JSON objects, see example below. (3) watch and filter logs using a log querying API (built-in in most loggers) or a log viewer software
|
||||
(4) Expose and curate log statement for the operation team using operational intelligence tool like Splunk
|
||||
|
||||
|
||||
### Code Example – explanation
|
||||
|
||||
### Code Example – Winston Logger in action
|
||||
|
||||
```javascript
|
||||
code here
|
||||
//your centralized logger object
|
||||
var logger = new winston.Logger({
|
||||
level: 'info',
|
||||
transports: [
|
||||
new (winston.transports.Console)(),
|
||||
new (winston.transports.File)({ filename: 'somefile.log' })
|
||||
]
|
||||
});
|
||||
|
||||
//custom code somewhere using the logger
|
||||
logger.log('info', 'Test Log Message with some parameter %s', 'some parameter', { anything: 'This is metadata' });
|
||||
|
||||
```
|
||||
|
||||
### Code Example – another
|
||||
### Code Example – Querying the log folder (searching for entries)
|
||||
|
||||
```javascript
|
||||
code here
|
||||
var options = {
|
||||
from: new Date - 24 * 60 * 60 * 1000, until: new Date, limit: 10, start: 0,
|
||||
order: 'desc', fields: ['message']
|
||||
};
|
||||
|
||||
|
||||
// Find items logged between today and yesterday.
|
||||
winston.query(options, function (err, results) {
|
||||
//callback with results
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
### Blog Quote: "Title"
|
||||
From the blog pouchdb.com, ranked 11 for the keywords “Node Promises”
|
||||
### Blog Quote: "Logger Requirements"
|
||||
From the blog Strong Loop
|
||||
|
||||
> …text here
|
||||
|
||||
### Image title
|
||||

|
||||
|
||||
|
||||
|
||||
> Lets identify a few requirements (for a logger):
|
||||
1. Time stamp each log line. This one is pretty self explanatory – you should be able to tell when each log entry occured.
|
||||
2. Logging format should be easily digestible by humans as well as machines.
|
||||
3. Allows for multiple configurable destination streams. For example, you might be writing trace logs to one file but when an error is encountered, write to the same file, then into error file and send an email at the same time…
|
||||
|
||||
Reference in New Issue
Block a user