-
Notifications
You must be signed in to change notification settings - Fork 93
Fixed bug with calling next Express middleware after sending response #3707
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: integration
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the delayed review. To me this looks ok for farm controller. But field controller actually has a next function in the express routes.
I am not sure the purpose, or if its still working, but there is a weather station id check that looks as though it is supposed to be run after sending a response.
|
@Ryszard-Trojnacki I haven't reviewed this one yet because although the change seems reasonable, I haven't had the time to dig into why the API tests are failing. Do you have a clue as to why that is? |
|
@antsgar It seems like the tests failing is on our end - for some reason it seems like despite approving the workflows to run on this external repo branch the environment variables did not get passed in as expected. |
|
@antsgar I have seen this API test error, but this isn't related to this PR. It is in all Pull requests that are remote (from forks). For example:
This is related to GitHub behaviour and
This makes a lot of sense, because I could make a PR with printing those secret variables. |
|
@Ryszard-Trojnacki excellent, I hadn't had the time to dig into it, makes sense to me too. Did you get a chance to see @Duncan-Brain's comment re the field route? It does seem like there's another middleware running after |
|
OK, I have checked this and @Duncan-Brain was right. Changes were made in two files:
router.post(
'/',
hasFarmAccess({ body: 'farm_id' }),
checkScope(['add:fields']),
fieldController.addField(),
fieldController.mapFieldToStation,
);handler for mapFieldsToStationId([field]);I have checked this and The second file router.post('/', farmController.addFarm());and therefore it doesn't require additional change. There are also global handlers added in
I hope that it is all right this time. |
| await trx.commit(); | ||
| req.field = { fieldId: result.field_id, point: result.grid_points[0] }; | ||
| const field = { fieldId: result.field_id, point: result.grid_points[0] }; | ||
| mapFieldsToStationId([field]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for looking at this, now what I am seeing is that we are changing the order of execution, and the function is also now covered by the try catch block.
So should this function fail, the response will not be sent. I still don't know anything about this function but the programmer who did it felt that it should not block a successful response from the other code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I understand this mapFieldsToStationId is a RxJS function and it is not blocking and will not throw exception.
It will create only the RxJS pipeline and return (not throwing exception not doint anything). Then, when request is handled it will be executed by pipeline steps which are async.
There are two places when an exception can be thrown:
getStationIdFromFieldbut it is catched withcatchErrorand logged to console.await insertStationToField(fieldData)and this is unhandled, but this will not throw and error in this call context.
As I understand RxJS (never used it) mapFieldsToStationId will never throw exception in this call context.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Ryszard-Trojnacki Yeah, I have no clue about how this RxJS works -- RxJS really seems overkill and unnecessary here. And I really don't understand the call context with RxJS.
Since this bug is not super high on our bug radar, and it is on such an important endpoint (AddField) , I don't quite feel comfortable not putting some time into learning RxJS or guaranteeing handling the error. So I cheated and asked an AI if there could be some unhandled errors and it seemed to believe that there are some chances:
- If fieldsWithNoStationId() rejects (e.g., DB failure), the promise is passed to from(fields), which won’t catch rejection unless fieldsWithNoStationId is explicitly awaited and wrapped in a try/catch.
- catchError should return something (e.g., an observable) to recover. Otherwise, it terminates the stream.
- .subscribe() does not catch async/await errors unless you use a try/catch inside the callback.
My thoughts are:
- Does this one specific endpoint actually cause the 404 error since it uses next() correctly? The others had no next middleware just the error handler, this one actually has next middleware. I think this should not cause a 404.
- If it does actually cause the error - can we leave it in for now -- I think we could make a tech-debt ticket to remove the
station_id,weather-stationstuff altogether -- I cannot find where it is used at all -- and if we go that route then @antsgar could set it's priority. - Follow AI guidelines - least favourite option - inside the function top level try/catch, handle catchError() correctly with return, try/catch and error in subscribe()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First of all fieldsWithNoStationId() is never called in this scenario. This method mapFieldsToStationId is always called with parameter in this context:
mapFieldsToStationId([field]);then:
const fields = fieldsToSet ? Promise.resolve(fieldsToSet) : fieldsWithNoStationId();fieldsToSet is set to [field] and Promise.resolve(fieldsToSet) is returned, not fieldsWithNoStationId().
Next what is called is:
concatMap((field) => from(getStationIdFromField(field)).pipe(delay(1000))),and getStationIdFromField is a Promise then it cannot throw exception in mapFieldsToStationId call.
And last I can just wrap this call in try catch, but still I think if there is throw an error, then it should be handled/fixed, not ignored like now. Now response is send to user and if an exception happens it is ignored.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point about the first line. I do still wonder if a 404 is possible here since next() points to this function correctly unlike the other endpoints.
I think the deeper issue for me is it is possibly just unused code so I might prefer to address this one in another PR and accept the other good fixes you have here
|
|
||
| // eslint-disable-next-line no-unused-vars | ||
| mapFieldToStation(req, res) { | ||
| mapFieldToStation(req, _res) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Depending on the solution, is this function necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, I don't think so. I didn't want to remove code that maybe someone would need to use in future.
… in `farmController.js` and `fieldController.js`.
9be9daf to
5d8e44a
Compare
Description
There were few places in code when response was send (
res.send) and then callednext()middleware from ExpressJS.This caused error in response, because
404handler was executed and tried to send response (statusheader) once again.The exception:
Code causing error:
Status is set
res.status(400)thennext()is called which exececutes error handler, which trying once again statusres.status(error.status || 500);Jira link: N/A
Type of change
How Has This Been Tested?
Tested on self hosted server before there was an error in console now this error not happens.