- 1. Dependency management
Issue 1.1: Suddenly my apps stopped working in production because of some updates!
To update package outdated using: npm updateRecommend to use the specific version on the package
Don't add an unnecessary try-catch. If you don't know the Customer always an array, then you always know that there will be a for each method. So, don't need to add array check like that
You should know data structures in your codebase. If you know that some customers don't have a payments property then you should check it using IF condition to check don't you try-catch around it.
DON'T
Never catch Programming errors - They have to be fixed- For unknown programming errors, the app must crash, fail loudly, then fix
- 2. Error handling
- Always handle operational errors: Let's just say you have here an express handler and you execute some HTTP request that means an external system is involved and whenever you have external systems or user input or whatever outside your program then they will always go wrong at some point in time. There's not a single external system that is available all the time maybe the connection is broken, or the external function error...etc. So, always make sure to handle those errorsIn this case, this function could be throw in if the system is not available so you have to catch it, no other way to do it if excecueHttpRequest throw some time you can get the status of the response then you can check on httpResponse but if this functions throws then you have to catch it then log it and send status 502 for the bad gateway for example.
CAP's remote service API does this automatically if you use CAP and you have here a handler to read books and you take external services (extSrv) and you run this query on it and we find out that this external service is not there then we automatically that gateway so you don't have to deal with its income.
Issue: After some point in time, my app stops working properly.If you look at the code this is the express middleware to catch all errors that means you catch and you can see it because it has four Argument(err,req, res, next) this way you catch all errors which happen during runtime and just send status 500 to the caller which sounds reasonable at first glance. But the problem is that all arrows are caught, which means you are also catching unexpected errors in programming.
CAP server also crashes when there are programming errors so we have to central error handler but we always check that if it's one of those
err instance of TypeError ||err instance of ReferenceError||
err instance of SyntaxError ||
err instance of RangeError ||
err instance of URIError||
Issue: There's an error in my app, but I can't find the root cause
This is very common something like this, you get a stack trace with some error that happened, and you don't know where has error happenedThe reason: The error lose information when you try to re-throwing errors
Solution:Using object assign some new property like that
Then you will see an error like this with the original error at the importantFunction Then we can figure out what is the root cause.
- 3. Transaction handling
Issue: After the first request, my app doesn't respond anymore!
This is a very common issue. Take a look at the code below it to seem good but something mission as an argument of tx function you don't provide the request object to tx
Reason: cds.tx() start a new (unmanaged) transaction which you have to commit and roll back manually.Solution: You have to provide req to tx
- Database always start from the beginning and end with commit/rollback- SQLite no parallel so you could have a deadlock if one transaction is not committed - Provide req to link lifecycle transaction to request when the request is succeeded we automatically perform a commit.
Example 2: You have a request then during the request at some point you have database interaction -> then automatically send a begin -< then we immediately register handlers for the succeeded, failed event of the requestIf success we perform a commitif failed we perform rollbackThen execute SQLIssue: After the first request to my express handler, my app doesn't respond anymore
First look you see everything is good you provided the req but the problem is it's not find because the req here is express request, not CAP request these are different things
Solution: You can't use them interchangeably so once you're in express, you need to use your own transactions and manage them on your own like this.
Select from the book is actually a cqn object an object representing the query but if you await this then we execute it we'll look at the corresponding transaction to join it to that transaction and it's a bit like magic because we don't provide any rack object here.So, how does it work how does the CAP framework know which transaction to use which tenant to use, which locate to use?
The cds is global object so that context is also a global object.But it's not global variable it's local with respect to the async context
Issue: Background database operations have a strange broker
In this example code, you can see that you run backgroundTask then we await a SQL and object. This is a continuation of which transaction to use to join it to. But then you will have nasty race conditions because we use the same transaction and the original request but we don't await the result and that is super nasty. So, this is really problematic and you have race conditions.
Issue: After the first request, my app doesn't respond anymore!
This is a very common issue. Take a look at the code below it to seem good but something mission as an argument of tx function you don't provide the request object to tx
Reason: cds.tx() start a new (unmanaged) transaction which you have to commit and roll back manually.
Solution: You have to provide req to tx
- Database always start from the beginning and end with commit/rollback
- SQLite no parallel so you could have a deadlock if one transaction is not committed
- Provide req to link lifecycle transaction to request when the request is succeeded we automatically perform a commit.
If success we perform a commit
if failed we perform rollback
Then execute SQL
Solution: You can't use them interchangeably so once you're in express, you need to use your own transactions and manage them on your own like this.
The cds is global object so that context is also a global object.But it's not global variable it's local with respect to the async context
- 4. Database pool Configuration
Issue: Some requests fail during high load
There are some potential issues that cause for this problem one course could be for example that you didn't allocate enough memory for your application and in cloud foundry, it's directly correlated to how much CPU you get the more memory you provide the more CPU you get that could be a problem that you run out of memoryReason: you configure your pool in a wrong way or in a bad way
Solution: Most important optionsacquireTimeoutMillis: give you an option to set how long you're allowed to wait to get to acquire a connection out of this pool and if it takes too long throw an error and usually this is set to belittle and that's why some requests get 503max : is the maximum amount of connections we keep in our pool
Unfortunately, there's no one-size-fits-all solution so you have to test how to adjust these on your application.
There are some potential issues that cause for this problem one course could be for example that you didn't allocate enough memory for your application and in cloud foundry, it's directly correlated to how much CPU you get the more memory you provide the more CPU you get that could be a problem that you run out of memory
- 5. Loggin
Issue: Can't use Kibana to analyze the logs
Normally the log was written like that console.log('My log output');Kibana can't read the log by this waySolution:- 6. Generic handlers
Issue: How can i register generic handlers for all services?Solution:
create class MyAppService extend our usual application serviceThen you can do whatever you want, you can override the init function for example which happens during bootstrapthen you can write a call super init, register some handler that always runs, always perform some log output
- 7. Environment
Issue: How can i easily switch my environment?Solution: CAP provides profiles which allows you exactly to do it
cds env --profile <profile>cds run --profile <profile>
Example:dblocal: using sqliteproduction: using hana
- 8. Testing
Use cds.test for automatically test
How to use:First create the path to your project, for example you can use a path to join current directory with ".." to go one
Example code
- 9. REPL
create class MyAppService extend our usual application service
Then you can do whatever you want, you can override the init function for example which happens during bootstrap
then you can write a call super init, register some handler that always runs, always perform some log output
Using CDS REPL to play around all the CAP API and javascript dynamic language and it has great support for the REPL so we should make use of it.
Just write cds repl
And now you're in the REPL and you can also do for example you can write const t equals cds.test('./') for this root directory.
await t.GET('/catalog/Books')
Then you will get the response of your Books
You can also connect to the service and get the books
You can also be using raw SQL for select data.
Source: https://www.youtube.com/watch?v=WTOOse-Flj8
Không có nhận xét nào:
Đăng nhận xét