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

feat: rate limit requests using aperture #14

Merged
merged 10 commits into from
Dec 15, 2023
Merged

Conversation

gitcommitshow
Copy link
Owner

@gitcommitshow gitcommitshow commented Dec 11, 2023

Summary by CodeRabbit

  • New Features

    • Integrated rate limiting for API requests to enhance performance and comply with GitHub API guidelines.
  • Refactor

    • Updated request-making logic to utilize the new rate limiting feature.
  • Documentation

    • Adjusted code comments to reflect changes in request functions and parameters.

Copy link
Contributor

coderabbitai bot commented Dec 11, 2023

Walkthrough

The codebase has been updated to handle rate limiting when making HTTP requests to the GitHub API. A new function makeRequestWithRateLimit has been introduced, and the existing makeRequest function now accepts rate limit options. Additionally, an Aperture client has been integrated to manage these rate limits.

Changes

File(s) Summary
network.js Added a new dependency @fluxninja/aperture-js. Added makeRequestWithRateLimit function for rate-limited HTTPS requests. Added getApertureClient function to initialize and return an Aperture client. Renamed options parameter to requestOptions in makeRequest function.
test/index.test.js Added import statement for 'dotenv/config' for environment configuration.
.github/workflows/test.yml Introduces APERTURE_SERVICE_ADDRESS and APERTURE_API_KEY environment variables sourced from secrets for workflow configuration.

🐇✨
Code hops along, no more delay,
With rate limits in a smart array.
Requests flow with ease and grace,
Thanks to Aperture's steady pace.
🌟🚀

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on X ?


Tips

Chat with CodeRabbit Bot (@coderabbitai)

  • You can reply to a review comment made by CodeRabbit.
  • You can tag CodeRabbit on specific lines of code or files in the PR by tagging @coderabbitai in a comment.
  • You can tag @coderabbitai in a PR comment and ask one-off questions about the PR and the codebase. Use quoted replies to pass the context for follow-up questions.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger a review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • The JSON schema for the configuration file is available here.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/coderabbit-overrides.v2.json

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Review Status

Actionable comments generated: 5

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 5397704 and 2b71564.
Files selected for processing (2)
  • contributors.js (3 hunks)
  • network.js (3 hunks)
Additional comments: 8
contributors.js (5)
  • 13-13: The import statement has been correctly updated to use the new makeRequestWithRateLimit function from network.js. This aligns with the PR objectives.

  • 46-46: The makeRequestWithRateLimit function is called with the correct parameters, and the response is destructured to obtain res and data. Ensure that the makeRequestWithRateLimit function is designed to return an object with these properties.

  • 74-74: Similar to the previous hunk, the makeRequestWithRateLimit function is used correctly here. Verify that the function returns an object with res and data properties.

  • 71-77: The pagination logic in getRepoContributors seems correct, and the function is using the makeRequestWithRateLimit function as expected. Ensure that the makeRequestWithRateLimit function handles pagination internally or that the calling function correctly interprets when to stop paginating.

  • 71-77: The data processing functions aggregateAllContributors and sortReposByContributionsCount are not directly affected by the changes in this PR. However, ensure that the data structure returned by the makeRequestWithRateLimit function is compatible with the expected input for these functions.

network.js (3)
  • 114-114: The FlowStatus used in flow.setStatus(FlowStatus.Error); is not defined in the provided code. Please ensure that FlowStatus is imported or defined within the scope.

  • 101-102: The deadline set for the gRPC call in makeRequestWithRateLimit is very short (300 milliseconds). Please verify if this is the intended behavior.

  • 77-80: The rateLimitOptions parameter in makeRequestWithRateLimit is not being used. Please clarify its intended usage and implement it if necessary.

network.js Outdated
Comment on lines 96 to 110
const flow = await apertureClient.startFlow("external-api-request", {
labels: {
url: url,
},
grpcCallOptions: {
deadline: Date.now() + 300, // ms
},
});

if (flow.shouldRun()) {
// Add business logic to process incoming request
console.log("Request accepted. Processing...");
const {res, data} = await makeRequest(...arguments)
return { res, data}
Copy link
Contributor

Choose a reason for hiding this comment

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

The use of ...arguments in makeRequestWithRateLimit could lead to maintenance issues. It's better to explicitly pass the method, url, and requestOptions to makeRequest.

- const {res, data} = await makeRequest(...arguments)
+ const {res, data} = await makeRequest(method, url, requestOptions)

Committable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
async function makeRequestWithRateLimit(method, url, requestOptions){
const flow = await apertureClient.startFlow("external-api-request", {
labels: {
url: url,
},
grpcCallOptions: {
deadline: Date.now() + 300, // ms
},
});
if (flow.shouldRun()) {
// Add business logic to process incoming request
console.log("Request accepted. Processing...");
const {res, data} = await makeRequest(...arguments)
return { res, data}
async function makeRequestWithRateLimit(method, url, requestOptions){
const flow = await apertureClient.startFlow("external-api-request", {
labels: {
url: url,
},
grpcCallOptions: {
deadline: Date.now() + 300, // ms
},
});
if (flow.shouldRun()) {
// Add business logic to process incoming request
console.log("Request accepted. Processing...");
const {res, data} = await makeRequest(method, url, requestOptions)
return { res, data}

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Review Status

Actionable comments generated: 4

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 2b71564 and d963463.
Files ignored due to filter (2)
  • package-lock.json
  • package.json
Files selected for processing (2)
  • contributors.js (3 hunks)
  • network.js (3 hunks)
Additional comments: 6
contributors.js (3)
  • 9-9: The import statement includes both makeRequest and makeRequestWithRateLimit, but the summary suggests makeRequest was replaced. Verify if makeRequest is still being used elsewhere in the codebase or if it should be removed from the import.

The import statement in contributors.js correctly includes both makeRequest and makeRequestWithRateLimit. The makeRequest function is still present in network.js, indicating it's likely still in use. No further action is required regarding this import.

  • 42-42: The change to use makeRequestWithRateLimit in getAllRepos aligns with the PR objective to introduce rate limiting.

  • 70-70: The change to use makeRequestWithRateLimit in getRepoContributors is consistent with the PR objective to introduce rate limiting.

network.js (3)
  • 7-15: Lazy initialization of apertureClient seems correctly implemented.

  • 22-24: The documentation update for makeRequest correctly reflects the new parameter structure.

  • 94-118: The implementation of makeRequestWithRateLimit correctly uses the apertureClient to control the flow of requests based on rate limiting.

network.js Outdated
Comment on lines 104 to 113
if (flow.shouldRun()) {
// Add business logic to process incoming request
console.log("Request accepted. Processing...");
const {res, data} = await makeRequest(...arguments)
return { res, data}
} else {
console.log("Request rate-limited. Try again later.");
// Handle flow rejection
flow.setStatus(FlowStatus.Error);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

The makeRequestWithRateLimit function should throw an error or return a rejected promise when the request is rate-limited, as previously suggested.

+      console.log("Request rate-limited. Try again later.");
+      // Handle flow rejection
+      flow.setStatus(FlowStatus.Error);
+      throw new Error("Request rate-limited. Try again later.");

Committable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
if (flow.shouldRun()) {
// Add business logic to process incoming request
console.log("Request accepted. Processing...");
const {res, data} = await makeRequest(...arguments)
return { res, data}
} else {
console.log("Request rate-limited. Try again later.");
// Handle flow rejection
flow.setStatus(FlowStatus.Error);
}
if (flow.shouldRun()) {
// Add business logic to process incoming request
console.log("Request accepted. Processing...");
const {res, data} = await makeRequest(...arguments)
return { res, data}
} else {
console.log("Request rate-limited. Try again later.");
// Handle flow rejection
flow.setStatus(FlowStatus.Error);
throw new Error("Request rate-limited. Try again later.");
}

@@ -39,7 +39,7 @@ export async function getAllRepos(owner=REPO_OWNER, options) {
GITHUB_REQUEST_OPTIONS.headers["Authorization"] = "token "+options.GITHUB_PERSONAL_TOKEN;
Copy link
Contributor

Choose a reason for hiding this comment

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

The previous comment about the potential side effects of modifying GITHUB_REQUEST_OPTIONS directly is still valid. Consider creating a new options object within the function scope to avoid potential side effects.

Comment on lines 43 to 45
console.log("Repo list request finished");
console.log('HTTP status: ', res.statusCode);
// console.log(data)
Copy link
Contributor

Choose a reason for hiding this comment

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

The previous comment about ensuring proper error handling in case the request fails or the status code indicates an error is still valid. Consider adding explicit error handling to manage different HTTP status codes and request failures.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Review Status

Actionable comments generated: 2

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between d963463 and 0c922d8.
Files ignored due to filter (2)
  • package-lock.json
  • package.json
Files selected for processing (3)
  • .github/workflows/test.yml (1 hunks)
  • network.js (3 hunks)
  • test/index.test.js (1 hunks)
Files skipped from review due to trivial changes (1)
  • .github/workflows/test.yml
Additional comments: 6
network.js (4)
  • 2-15: The lazy initialization of ApertureClient in getApertureClient is a good practice to avoid unnecessary instantiation if the client is not used.

  • 22-24: Renaming of options to requestOptions and the addition of body and headers in the JSDoc comments is consistent and improves clarity.

  • 106-108: Ensure that the environment variables APERTURE_SERVICE_ADDRESS and APERTURE_API_KEY are correctly set for the ApertureClient to function properly.

Verification successful

The executed script confirms that the APERTURE_SERVICE_ADDRESS and APERTURE_API_KEY environment variables are not set in the current environment. However, this does not necessarily mean that there is an issue with the codebase itself. The environment variables are typically set in the deployment environment or through a configuration file, and it is not the responsibility of the codebase to set them.

The code snippet provided in the review comment suggests that the application logs an error and a couple of informational messages if the ApertureClient is not set up correctly, which is a reasonable way to handle the situation where the environment variables are not set. The application then proceeds to make the request without rate limiting.

Given this information, the code appears to handle the scenario of missing environment variables appropriately by notifying the user and falling back to a non-rate-limited request.

Scripts Executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Verify that the required environment variables are set
echo "Checking for APERTURE_SERVICE_ADDRESS and APERTURE_API_KEY environment variables..."
if [[ -z "$APERTURE_SERVICE_ADDRESS" || -z "$APERTURE_API_KEY" ]]; then
  echo "Environment variables for ApertureClient are not set."
else
  echo "Environment variables for ApertureClient are set."
fi

Length of output: 307

* 119-125: Verify that `FlowStatus.Error` is a valid status and ensure that `flow.end()` is called to properly clean up the flow after it's no longer needed.
Verification successful

FlowStatus.Error and flow.end() are both present in network.js, which confirms their validity in the context of the codebase.

Scripts Executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Verify that FlowStatus.Error is a valid status
ast-grep --lang javascript --pattern $'enum FlowStatus {
  $$$
  Error($_)
  $$$
}'

Length of output: 550



Script:

#!/bin/bash
# Verify that FlowStatus.Error is a valid status by checking if it's a property of an object
ast-grep --lang javascript --pattern $'const FlowStatus = {
  $$$
  Error: $_,
  $$$
}'

# Verify that the flow.end() method exists
ast-grep --lang javascript --pattern $'class $_ {
  $$$
  end() {
    $$$
  }
  $$$
}'

Length of output: 176



Script:

#!/bin/bash
# Use ripgrep to search for FlowStatus.Error and flow.end() in the codebase
rg "FlowStatus\.Error" --files-with-matches
rg "flow\.end\(\)" --files-with-matches

Length of output: 109

test/index.test.js (2)
  • 1-1: Ensure that the environment variables loaded by 'dotenv/config' are actually used in the tests. If not, this import might be unnecessary.

  • 2-7: The import statements and test suite setup appear to be correct and consistent with typical Mocha test files.

Comment on lines +59 to +60
if (requestOptions.data) {
req.write(requestOptions.data);
Copy link
Contributor

Choose a reason for hiding this comment

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

The previous comment about renaming requestOptions.data to requestOptions.body has not been addressed. This should be consistent with the JSDoc comments and the rest of the codebase.

- if (requestOptions.data) {
-     req.write(requestOptions.data);
+ if (requestOptions.body) {
+     req.write(requestOptions.body);

Committable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
if (requestOptions.data) {
req.write(requestOptions.data);
if (requestOptions.body) {
req.write(requestOptions.body);

network.js Outdated
Comment on lines 97 to 103
flow = await getApertureClient().startFlow("external-api", {
labels: {
url: url,
},
grpcCallOptions: {
deadline: Date.now() + 300, // ms
},
Copy link
Contributor

Choose a reason for hiding this comment

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

The deadline in grpcCallOptions is set to Date.now() + 300, which is likely incorrect as Date.now() returns the number of milliseconds since January 1, 1970, and adding 300 would still represent a time in the past. The deadline should be set to a future time.

- deadline: Date.now() + 300, // ms
+ deadline: Date.now() + 300000, // 300 seconds in the future

Committable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
flow = await getApertureClient().startFlow("external-api", {
labels: {
url: url,
},
grpcCallOptions: {
deadline: Date.now() + 300, // ms
},
flow = await getApertureClient().startFlow("external-api", {
labels: {
url: url,
},
grpcCallOptions: {
deadline: Date.now() + 300000, // 300 seconds in the future
},

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Review Status

Actionable comments generated: 0

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 0c922d8 and 062955f.
Files selected for processing (1)
  • network.js (3 hunks)
Files skipped from review due to trivial changes (1)
  • network.js

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Review Status

Actionable comments generated: 0

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 062955f and 7f9ff05.
Files selected for processing (1)
  • network.js (3 hunks)
Files skipped from review as they are similar to previous changes (1)
  • network.js

@gitcommitshow gitcommitshow merged commit 72ff15b into main Dec 15, 2023
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant