Skip to content
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

Reducing cache-control for scheduled transactions. #9327

Open
wants to merge 24 commits into
base: main
Choose a base branch
from

Conversation

mgoelswirlds
Copy link
Member

@mgoelswirlds mgoelswirlds commented Sep 11, 2024

Description:
Reduce cache for the transactions endpoint with scheduled transactions.

This PR modifies

  • Reduces the value of max-age for ScheduleCreate transactions
  • Changes the way content-type is set for the /network/supply endpoint

Related issue(s):

Fixes #9174

Notes for reviewer:
Checklist

  • Documented (Code comments, README, etc.)
  • Tested (unit, integration, etc.)

@mgoelswirlds mgoelswirlds self-assigned this Sep 11, 2024
@mgoelswirlds mgoelswirlds added enhancement Type: New feature rest Area: REST API labels Sep 11, 2024
@mgoelswirlds mgoelswirlds added this to the 0.114.0 milestone Sep 11, 2024
Copy link

codecov bot commented Sep 11, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 92.68%. Comparing base (90dca10) to head (45ab8c3).
Report is 2 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff            @@
##               main    #9327   +/-   ##
=========================================
  Coverage     92.68%   92.68%           
  Complexity     6943     6943           
=========================================
  Files           896      896           
  Lines         29553    29576   +23     
  Branches       3745     3751    +6     
=========================================
+ Hits          27390    27412   +22     
  Misses         1399     1399           
- Partials        764      765    +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Signed-off-by: mgoelswirlds <[email protected]>
@mgoelswirlds mgoelswirlds marked this pull request as ready for review September 11, 2024 15:02
hedera-mirror-rest/middleware/responseHandler.js Outdated Show resolved Hide resolved
hedera-mirror-rest/middleware/responseHandler.js Outdated Show resolved Hide resolved
hedera-mirror-rest/transactions.js Outdated Show resolved Hide resolved
hedera-mirror-rest/transactions.js Outdated Show resolved Hide resolved
hedera-mirror-rest/transactions.js Outdated Show resolved Hide resolved
hedera-mirror-rest/transactions.js Outdated Show resolved Hide resolved
import {
requestPathLabel,
requestStartTime,
responseContentType,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should update network supply to use the new response headers and remove responseContentType to make it consistent and not have two ways to possibly set content type.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did try changing this. Works for network supply but many other tests fail complaining about the Invalid media type. Looking further into what needs to be resolved here.

hedera-mirror-rest/transactions.js Outdated Show resolved Hide resolved
hedera-mirror-rest/transactions.js Outdated Show resolved Hide resolved
hedera-mirror-rest/transactions.js Outdated Show resolved Hide resolved
hedera-mirror-rest/transactions.js Outdated Show resolved Hide resolved
hedera-mirror-rest/transactions.js Outdated Show resolved Hide resolved
hedera-mirror-rest/transactions.js Outdated Show resolved Hide resolved
@mgoelswirlds
Copy link
Member Author

mgoelswirlds commented Sep 16, 2024

I still need to address the new comments on the PR @steven-sheehy
I mistakenly asked for a re-review.

hedera-mirror-rest/transactions.js Outdated Show resolved Hide resolved
hedera-mirror-rest/transactions.js Outdated Show resolved Hide resolved
hedera-mirror-rest/transactions.js Outdated Show resolved Hide resolved
hedera-mirror-rest/transactions.js Outdated Show resolved Hide resolved
Removing the use of responseHeadersLabel.

Signed-off-by: mgoelswirlds <[email protected]>
Signed-off-by: mgoelswirlds <[email protected]>
Signed-off-by: mgoelswirlds <[email protected]>
Signed-off-by: mgoelswirlds <[email protected]>
Signed-off-by: mgoelswirlds <[email protected]>
hedera-mirror-rest/middleware/responseHandler.js Outdated Show resolved Hide resolved
hedera-mirror-rest/transactions.js Outdated Show resolved Hide resolved
hedera-mirror-rest/transactions.js Outdated Show resolved Hide resolved
Signed-off-by: mgoelswirlds <[email protected]>
expect(mockResponse.set).toHaveBeenNthCalledWith(1, headers.default);
expect(mockResponse.set).toHaveBeenNthCalledWith(2, headers.path[mockRequest.route.path]);
expect(mockResponse.set).toHaveBeenNthCalledWith(3, 'Content-Type', 'application/json; charset=utf-8');
expect(mockResponse.set).toHaveBeenCalledWith({'Content-type': 'application/json; charset=utf-8'},headers.path[mockRequest.route.path]);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have spent a lot of time trying to fix these 2 tests with this new approach. But have not been successful.
Would like to get the other parta approved and continue working on these on the side.

@@ -363,8 +363,13 @@ const getSuccessProtoIds = () => {
];
};

const isSuccessful = (result) => {
return getSuccessProtoIds().includes(result);
Copy link
Member

@steven-sheehy steven-sheehy Sep 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For performance, we should calculate getSuccessProtoIds() once and store as a static. Prior to this method, its other uses were separately cached so it wasn't a concern. Now it's called in a loop inside our highest used API.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added a constant which calls getSuccessProtoIds() once.


const code = res.locals.statusCode;
const contentType = res.locals[responseContentType] || APPLICATION_JSON;
const contentType = mergedHeaders['Content-type'];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use CONTENT_TYPE_HEADER here and other places that put responseHeadersLabel

Comment on lines 54 to 58
const contentType = mergedHeaders['Content-type'];

const linksNext = res.locals.responseData.links?.next;
res.status(code);
res.set(CONTENT_TYPE_HEADER, contentType);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't need to set content-type header since it should've already been set above via res.set(mergedHeaders).

Suggested change
const contentType = mergedHeaders['Content-type'];
const linksNext = res.locals.responseData.links?.next;
res.status(code);
res.set(CONTENT_TYPE_HEADER, contentType);
const linksNext = res.locals.responseData.links?.next;
res.status(code);

Comment on lines +46 to +51
const mergedHeaders = {
...headers.default,
...(headers.path[path] ?? {}),
...(res.locals[responseHeadersLabel] ?? {}),
};
res.set(mergedHeaders);
Copy link
Member

@steven-sheehy steven-sheehy Sep 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have to be careful since HTTP headers are case insensitive but this mergedHeaders object is not. However, express set() should be case insensitive. We should have a unit test that has different mixed case for default, path and responseHeadersLabel and ensure they are all merged into one entry returned via res.get()

Copy link
Member Author

@mgoelswirlds mgoelswirlds Sep 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried adding a unit test, but that would need to work with mocking the result and then there seemed no point to hardcode what set and get would do.
This needs fixing but this was the tentative test:

  test('should merge headers in a case insesitive manner', async () => {
    const path = '/api/v1/transactions/:transactionId';
    headers.path[path] = { "Cache-control": "public, max-age=1",
      "content-Type": "application/json; charset=utf-8" };
    mockResponse.locals[responseHeadersLabel] = { "cache-Control": "public, max-age=1",
      "Content-type": 'text/plain; charset=utf-8' };
    await responseHandler(mockRequest, mockResponse, null);
    expect(mockResponse.get('content-type')).toHaveLastReturnedWith(mockResponse.locals[responseHeadersLabel]['Content-type']);
  });

The network/supply spec tests do test the case insensitiveness to some extend atleast for headers.default and res.locals[responseHeadersLabel]
If that is acceptable , I can work on a future PR to add a more comprehensive test for this .

Comment on lines 784 to 785
function getTransactionsByIdOrHashCacheControlHeader(transactionsRows, isTransactionHash, scheduled) {
if (scheduled || isTransactionHash) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I mentioned previously.

Suggested change
function getTransactionsByIdOrHashCacheControlHeader(transactionsRows, isTransactionHash, scheduled) {
if (scheduled || isTransactionHash) {
function getTransactionsByIdOrHashCacheControlHeader(transactionsRows) {
if (transactionsRows.length < 2) {

Copy link
Collaborator

@xin-hedera xin-hedera Sep 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not entirely true. it's possible to have scheduled=false query param and return multiple transactions for the same transaction id. Then we can have a successful schedulecreate in the response with all others failed, ideally we should use the longer max-age because the existence of the scheduled=? query param.

However given that such scenario happens rarely, and using a shorter max-age doesn't hurt function, agree we can go with the simpler approach.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I missed that this scheduled variable represents the query param exists and not that it exists and is set to true, hence my comment. We can keep the scheduled check but omit isTransactionHash and just use list size for that.

@@ -87,7 +87,8 @@ hedera:
response:
compression: true
headers:
default: { "cache-control": "public, max-age=1" }
default: { "cache-control": "public, max-age=1",
"Content-type": "application/json; charset=utf-8"}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use consistent casing.

Suggested change
"Content-type": "application/json; charset=utf-8"}
"content-type": "application/json; charset=utf-8"}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually other places in the code so you "Content-type" but will change it here.

Comment on lines 793 to 794
if (transaction.type === scheduleCreateProtoId) {
if (TransactionResult.isSuccessful(transaction.result)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can combine these two if statements since it's not like a schedule create can have scheduled=true

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok.

Comment on lines 802 to 803
if (successScheduleCreateTimestamp !== undefined
&& (utils.nowInNs() - successScheduleCreateTimestamp) < maxTransactionConsensusTimestampRangeNs ) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Readability

Suggested change
if (successScheduleCreateTimestamp !== undefined
&& (utils.nowInNs() - successScheduleCreateTimestamp) < maxTransactionConsensusTimestampRangeNs ) {
const elapsed = utils.nowInNs() - successScheduleCreateTimestamp;
if (successScheduleCreateTimestamp && elapsed < maxTransactionConsensusTimestampRangeNs ) {

Comment on lines +704 to +705
const isTransactionHash = isValidTransactionHash(transactionIdOrHash);
let scheduledParamExists = false;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Think updates to this method can be undone with my other comment.

@steven-sheehy steven-sheehy modified the milestones: 0.114.0, 0.115.0 Sep 18, 2024
hedera-mirror-rest/transactions.js Outdated Show resolved Hide resolved
hedera-mirror-rest/transactions.js Show resolved Hide resolved
hedera-mirror-rest/transactions.js Outdated Show resolved Hide resolved
hedera-mirror-rest/transactions.js Outdated Show resolved Hide resolved
Copy link

sonarcloud bot commented Sep 21, 2024

import {NotFoundError} from '../errors';
import {JSONStringify} from '../utils';

const {
response: {headers},
} = config;

const CONTENT_TYPE_HEADER = 'Content-Type';
const CONTENT_TYPE_HEADER = 'content-type';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why have the same constant defined in two places?

@xin-hedera
Copy link
Collaborator

I approved it since I'm off on Monday so don't unnecessarily block the PR. There is still one minor change I asked for.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Type: New feature rest Area: REST API
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Reduce cache for the transactions endpoint with scheduled transactions
3 participants