Skip to content

Apply Rate limiting #3359

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

Merged

Conversation

im-vedant
Copy link

@im-vedant im-vedant commented Mar 12, 2025

What kind of change does this PR introduce?

Issue Number:

Fixes #3309

Snapshots/Videos:

https://www.loom.com/share/03293131706d4dac8b009f3f48958c3b

Summary

  1. Query Cost Calculation: Integrated Pothos Complexity Plugin to assign complexity values to each GraphQL field, ensuring efficient query cost evaluation.

  2. Rate Limiting: Implemented Leaky Bucket Algorithm with Redis to enforce rate limits, preventing excessive API usage and maintaining system stability.

Does this PR introduce a breaking change?

Checklist

CodeRabbit AI Review

  • I have reviewed and addressed all critical issues flagged by CodeRabbit AI
  • I have implemented or provided justification for each non-critical suggestion
  • I have documented my reasoning in the PR comments where CodeRabbit AI suggestions were not implemented

Test Coverage

  • I have written tests for all new changes/features
  • I have verified that test coverage meets or exceeds 95%
  • I have run the test suite locally and all tests pass

Other information

Have you read the contributing guide?

Summary by CodeRabbit

  • New Features

    • Introduced a new Redis service for enhanced caching capabilities.
    • Enhanced API request handling with advanced rate limiting based on user authentication and query complexity.
    • Upgraded GraphQL operations with configurable complexity limits for optimized queries.
    • Expanded environment configurations to support Redis and complexity settings across development and production environments.
    • Added new properties to manage complexity costs for GraphQL fields.
    • Implemented a leaky bucket rate limiter for controlling request rates.
    • Added a new redis-test service for testing purposes.
    • Introduced a new network configuration for redis_test.
  • Bug Fixes

    • Improved handling of request complexity calculations to prevent exceeding rate limits.
  • Chores

    • Updated dependencies to include Redis and complexity management plugins.

Copy link

coderabbitai bot commented Mar 12, 2025

Caution

Review failed

The head commit changed during the review from 690b8f0 to 5a94ab0.

Walkthrough

This pull request introduces a Redis service to the Docker Compose configurations and integrates it into the Fastify server. Environment variable files are updated with Redis, GraphQL cost, and rate limiting settings. New dependencies are added to support Redis and GraphQL complexity plugins. The Fastify server now registers the Redis plugin and extends its instance with a new property. GraphQL resolvers across various types now include configurable complexity settings, and a new rate limiting mechanism using a leaky bucket algorithm is implemented to manage query loads.

Changes

File(s) Summary of Changes
compose.yaml, docker/compose.devcontainer.yaml, docker/compose.deploy.yaml, docker/compose.testing.yaml Added a new Redis service with health checks, network, volume, and port mapping configurations.
envFiles/.env.ci, envFiles/.env.devcontainer, envFiles/.env.deploy, envFiles/.env.production Introduced new environment variables for Redis (REDIS_MAPPED_HOST_IP, REDIS_MAPPED_PORT), GraphQL field costs, and rate limiting parameters.
package.json Added dependencies: @fastify/redis (^7.0.2) and @pothos/plugin-complexity (^4.1.0).
src/createServer.ts Registered the fastifyRedis plugin and added a configuration to connect to Redis using environment variables.
src/envConfigSchema.ts Extended the configuration schema to include new properties for Redis and GraphQL (field costs, mutation base cost) and rate limiting values.
GraphQL Files
(src/graphql/builder.ts,
src/graphql/types/...)
Integrated the ComplexityPlugin in the schema builder and updated field definitions in Organization, User, and Query types to include complexity configurations based on environment settings.
src/routes/graphql.ts Enhanced the GraphQL route by adding a preExecution hook to compute query complexity, perform rate limiting via the leaky bucket function, and manage caching behavior.
Utility Files
(src/utilities/graphqLimits.ts,
src/utilities/leakyBucket.ts)
Introduced a new module for validating GraphQL limit configurations and a leaky bucket algorithm to implement rate limiting for incoming requests.

Sequence Diagram(s)

sequenceDiagram
    participant C as Client
    participant F as Fastify GraphQL Route
    participant L as LeakyBucket RateLimiter
    participant G as GraphQL Resolver

    C->>F: Send GraphQL request
    F->>F: PreExecution Hook: Evaluate query complexity
    F->>L: Check rate limit (leaky bucket)
    L-->>F: Return rate limit result
    alt Allowed
        F->>G: Process GraphQL query
        G-->>F: Return query result
        F-->>C: Send response
    else Exceeded
        F-->>C: Return error (rate limited)
    end
Loading

Possibly related PRs

Suggested reviewers

  • palisadoes

Suggested labels

ignore-sensitive-files-pr


🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

Our Pull Request Approval Process

Thanks for contributing!

Testing Your Code

Remember, your PRs won't be reviewed until these criteria are met:

  1. We don't merge PRs with poor code quality.
    1. Follow coding best practices such that CodeRabbit.ai approves your PR.
  2. We don't merge PRs with failed tests.
    1. When tests fail, click on the Details link to learn more.
    2. Write sufficient tests for your changes (CodeCov Patch Test). Your testing level must be better than the target threshold of the repository
    3. Tests may fail if you edit sensitive files. Ask to add the ignore-sensitive-files-pr label if the edits are necessary.
  3. We cannot merge PRs with conflicting files. These must be fixed.

Our policies make our code better.

Reviewers

Do not assign reviewers. Our Queue Monitors will review your PR and assign them.
When your PR has been assigned reviewers contact them to get your code reviewed and approved via:

  1. comments in this PR or
  2. our slack channel

Reviewing Your Code

Your reviewer(s) will have the following roles:

  1. arbitrators of future discussions with other contributors about the validity of your changes
  2. point of contact for evaluating the validity of your work
  3. person who verifies matching issues by others that should be closed.
  4. person who gives general guidance in fixing your tests

CONTRIBUTING.md

Read our CONTRIBUTING.md file. Most importantly:

  1. PRs with issues not assigned to you will be closed by the reviewer
  2. Fix the first comment in the PR so that each issue listed automatically closes

Other

  1. 🎯 Please be considerate of our volunteers' time. Contacting the person who assigned the reviewers is not advised unless they ask for your input. Do not @ the person who did the assignment otherwise.
  2. Read the CONTRIBUTING.md file make

Copy link

@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.

Actionable comments posted: 5

🧹 Nitpick comments (9)
docker/compose.devcontainer.yaml (2)

164-169: Redis service configuration for rate limiting.

Adding Redis is essential for implementing the Leaky Bucket Algorithm for rate limiting as mentioned in the PR objectives. The configuration is consistent with other services in the file.

Fix the indentation in the port mapping to be consistent with other service configurations:

  redis:
    ports:
-    - host_ip: ${REDIS_MAPPED_HOST_IP:?error}
-      name: redis
-      published: ${REDIS_MAPPED_PORT:?error}
-      target: 6379
+      - host_ip: ${REDIS_MAPPED_HOST_IP:?error}
+        name: redis
+        published: ${REDIS_MAPPED_PORT:?error}
+        target: 6379
🧰 Tools
🪛 YAMLlint (1.35.1)

[warning] 166-166: wrong indentation: expected 6 but found 4

(indentation)


178-180: Remove trailing spaces and excess blank lines.

Clean up the file by removing trailing spaces and limiting to one blank line at the end of the file.

  postgres_test_data:
-  
-
-
+
🧰 Tools
🪛 YAMLlint (1.35.1)

[error] 178-178: trailing spaces

(trailing-spaces)


[warning] 180-180: too many blank lines

(2 > 0) (empty-lines)

src/createServer.ts (1)

81-84: Ensure error handling for Redis connection.

The Redis plugin configuration looks good, but consider adding error handling for Redis connection failures. This is especially important as the rate limiting feature will depend on Redis availability.

 fastify.register(fastifyRedis, {
   host: fastify.envConfig.API_REDIS_HOST,
   port: fastify.envConfig.API_REDIS_PORT,
+  closeClient: true,
+  maxRetriesPerRequest: 3,
 });

+// Handle Redis connection errors
+fastify.addHook('onReady', async () => {
+  fastify.redis.on('error', (err) => {
+    fastify.log.error({ err }, 'Redis connection error');
+  });
+});
compose.yaml (1)

254-254: Fix missing newline at the end of file.

Add a newline at the end of the file to comply with YAML best practices and fix the linting error.

 postgres_data:
 redis_data:
+
🧰 Tools
🪛 YAMLlint (1.35.1)

[error] 254-254: no new line character at the end of file

(new-line-at-end-of-file)

src/utilities/leakyBucket.ts (2)

25-35: Consider potential concurrency conflicts when multiple requests initialize the bucket simultaneously.
If numerous requests arrive before one has time to write the initial bucket data, there could be race conditions leading to inconsistent token counts. Redis transactions or LUA scripts could address this potential edge case.


42-43: Switch to a logger rather than using console.log in production code.
Relying on console.log can clutter production logs or inadvertently reveal sensitive info. A structured logger helps manage and filter logs consistently.

- console.log("Tokens: ", tokens);
- console.log("Last Update: ", lastUpdate);
+ fastify.log.debug({ tokens, lastUpdate }, "Leaky bucket debug info");
src/envConfigSchema.ts (3)

236-242: Add JSDoc documentation for Redis configuration

The Redis host and port variables are missing detailed JSDoc documentation, unlike other configuration variables in the file. Add consistent documentation to improve code maintainability.

Consider adding documentation like this:

+/**
+ * Host address for the Redis server used by the rate limiting implementation.
+ */
API_REDIS_HOST: Type.String({
	minLength: 1,
}),
+/**
+ * Port number for the Redis server used by the rate limiting implementation.
+ */
API_REDIS_PORT: Type.Number({
	maximum: 65535,
	minimum: 0,
}),

243-258: Use JSDoc style comments for GraphQL complexity configuration

The complexity cost variables use inline comments rather than the JSDoc format used throughout the rest of the file. For consistency and better documentation, convert these to JSDoc style.

-//  cost of scalar field
+/**
+ * Cost assigned to scalar fields in GraphQL queries for complexity calculation.
+ */
API_GRAPHQL_SCALAR_FIELD_COST: Type.Number({
	minimum: 0,
}),
-// cost of object field
+/**
+ * Cost assigned to object fields in GraphQL queries for complexity calculation.
+ */
API_GRAPHQL_OBJECT_FIELD_COST: Type.Number({
	minimum: 0,
}),
-// cost of list field
+/**
+ * Cost assigned to list fields in GraphQL queries for complexity calculation.
+ */
API_GRAPHQL_LIST_FIELD_COST: Type.Number({
	minimum: 0,
}),
-// base cost of mutation
+/**
+ * Base cost assigned to all mutation operations for complexity calculation.
+ */
API_GRAPHQL_MUTATION_BASE_COST: Type.Number({
	minimum: 0,
}),

236-267: Consider adding more detailed documentation about the rate limiting implementation

The current comments don't provide enough context about how these configuration variables affect the rate limiting system. Adding more detailed documentation would help users understand how to configure the rate limiting properly.

For example, you could add a brief explanation about the leaky bucket algorithm and how these parameters work together to control the rate limiting behavior. This would be especially helpful for anyone configuring the API without prior knowledge of the implementation details.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0461912 and c07c2e1.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (16)
  • compose.yaml (5 hunks)
  • docker/compose.devcontainer.yaml (2 hunks)
  • envFiles/.env.ci (1 hunks)
  • envFiles/.env.devcontainer (1 hunks)
  • package.json (1 hunks)
  • src/createServer.ts (4 hunks)
  • src/envConfigSchema.ts (1 hunks)
  • src/graphql/builder.ts (1 hunks)
  • src/graphql/types/Organization/creator.ts (2 hunks)
  • src/graphql/types/Query/user.ts (2 hunks)
  • src/graphql/types/Query/venue.ts (2 hunks)
  • src/graphql/types/User/creator.ts (2 hunks)
  • src/graphql/types/User/organizationsWhereMember.ts (2 hunks)
  • src/routes/graphql.ts (6 hunks)
  • src/utilities/graphqLimits.ts (1 hunks)
  • src/utilities/leakyBucket.ts (1 hunks)
🧰 Additional context used
🪛 YAMLlint (1.35.1)
compose.yaml

[error] 254-254: no new line character at the end of file

(new-line-at-end-of-file)

docker/compose.devcontainer.yaml

[warning] 166-166: wrong indentation: expected 6 but found 4

(indentation)


[error] 178-178: trailing spaces

(trailing-spaces)


[warning] 180-180: too many blank lines

(2 > 0) (empty-lines)

🔇 Additional comments (28)
package.json (1)

11-11: Added new dependencies for Redis and GraphQL complexity management

The addition of @fastify/redis and @pothos/plugin-complexity aligns perfectly with the PR objectives to implement rate limiting using Redis and enhance GraphQL query complexity management.

Also applies to: 15-15

src/graphql/types/Query/user.ts (1)

9-9: Added complexity configuration to the user query

The integration of the complexity configuration using environment variables is a good practice, allowing for consistent and configurable query cost calculation across the GraphQL schema.

Also applies to: 24-24

src/graphql/builder.ts (1)

2-2:

❓ Verification inconclusive

GraphQL complexity plugin configuration

The setup of the ComplexityPlugin is well-integrated with the existing builder configuration. However, the defaultListMultiplier is set to 0, which means list fields won't add any additional complexity based on their length.

Verify that setting defaultListMultiplier to 0 is intentional. In most GraphQL rate limiting implementations, list fields typically have a multiplier to account for the additional resources needed to process multiple items:

Also applies to: 5-5, 14-18


🏁 Script executed:

#!/bin/bash
# Check if there are any list fields in the schema that might be affected by defaultListMultiplier: 0

# Look for list type definitions in GraphQL files
echo "Searching for list type definitions in GraphQL schema..."
rg '\[.*\]!' --type ts -g 'src/graphql/**/*.ts'

# Look for array returns in resolvers that might need complexity consideration
echo "Searching for array returns in resolvers..."
rg 'return \[.*\]' --type ts -g 'src/graphql/**/*.ts'

Length of output: 325


GraphQL Complexity Plugin Configuration: Verify defaultListMultiplier Usage

  • The configuration sets defaultListMultiplier to 0, which means that list fields do not add extra complexity by default. This could be intentional if the schema is designed to handle list fields differently or if list fields are effectively absent.
  • Our initial search for list-type definitions or array returns in the GraphQL files produced no output. However, given that the absence of evidence may be due to custom handling of lists or specific query patterns, please manually verify that list fields in your schema (or resolvers) do not require a nonzero multiplier.
  • Also, review the relevant configuration segments near lines 5-5 and 14-18 in the same file to ensure consistency with overall complexity calculations.
src/graphql/types/Query/venue.ts (1)

9-9: Added complexity configuration to the venue query

The complexity configuration is properly implemented for the venue query, maintaining consistency with other query fields. This ensures that all queries contribute appropriately to the overall rate limiting mechanism.

Also applies to: 24-24

src/graphql/types/User/creator.ts (2)

2-2: Good addition of config import.

Adding the GraphQL complexity limits from a centralized configuration demonstrates good maintainability practices.


74-74: Appropriate complexity setting for the creator field.

Adding the complexity cost to the creator field helps with query cost calculation, which is essential for the rate limiting feature being implemented. Using a centralized configuration value ensures consistency across different GraphQL fields.

src/graphql/types/Organization/creator.ts (2)

3-3: Good addition of config import.

Importing the GraphQL complexity limits from a centralized configuration is a good practice.


104-104: Appropriate complexity setting for the creator field.

Adding the complexity cost to the Organization creator field maintains consistency with the User creator field implementation and contributes to the overall query cost calculation strategy.

src/utilities/graphqLimits.ts (1)

1-18: Well-structured configuration module for GraphQL limits.

This module is well-designed and adheres to good engineering practices:

  1. It uses type-safe schema validation via TypeBox
  2. It selectively imports only the necessary configuration fields
  3. It leverages environment variables for configuration
  4. It follows the existing pattern for environment configuration

This approach ensures that GraphQL complexity limits are consistently applied across the application.

src/createServer.ts (3)

5-5: Good addition of Redis support.

Adding Redis functionality to your application using the Fastify plugin is a good approach for the rate limiting implementation.


68-68: Properly initialized property.

Initializing the currentRequest property to null is correct, as it ensures the property exists before any request handling starts.


24-24:

❓ Verification inconclusive

Verify usage of the currentRequest property.

The currentRequest property is added to the FastifyInstance interface, but its usage is not evident from this file alone. Make sure this property is properly utilized in the rate limiting implementation.


🏁 Script executed:

#!/bin/bash
# Search for usage of currentRequest property
rg "currentRequest" --type ts

Length of output: 436


Verified Usage of currentRequest in Codebase

  • The property is declared and decorated in src/createServer.ts:
    • 	currentRequest: FastifyRequest | null;
      	...
      	fastify.decorate("currentRequest", null);
  • It is actively used in src/routes/graphql.ts:
    • The request object is assigned via:
      fastify.currentRequest = request;
    • Subsequent usage includes extracting the IP address and performing JWT verification:
      const ip = fastify.currentRequest?.ip;
      if (!fastify.currentRequest) {
        await fastify.currentRequest.jwtVerify<ExplicitAuthenticationTokenPayload>();
      }

While the property is indeed being used, its integration with the rate limiting implementation isn’t directly evident from these snippets. Please verify that the overall rate limiting logic leverages currentRequest as intended.

compose.yaml (4)

7-7: Good network configuration.

Adding a dedicated Redis network is the right approach for service isolation.


33-36: Proper dependency configuration.

The dependency configuration is correct, ensuring the API service waits for Redis to be healthy before starting. The required: false flag is appropriate to allow the service to operate with an external Redis instance.


74-75: Good environment variable configuration.

The Redis host and port environment variables are properly defined for the API service.


231-246: Robust Redis service configuration.

The Redis service configuration looks good with proper health check, networking, and volume setup. Using the Alpine version of Redis is a good choice for minimizing container size.

envFiles/.env.devcontainer (2)

107-112: GraphQL field cost configuration looks good.

The GraphQL cost configuration looks sensible with appropriate values for different field types. This will help in calculating the complexity of queries to implement rate limiting based on query cost.


120-121: Good Redis mapping configuration.

The Redis host and port mappings are correctly defined for local development.

envFiles/.env.ci (2)

77-82: GraphQL field cost configuration looks good.

The GraphQL cost configuration for CI environment is identical to the development environment, which ensures consistency across environments.


90-91: Good Redis mapping configuration for CI.

The Redis mappings are correctly defined for the CI environment.

src/graphql/types/User/organizationsWhereMember.ts (4)

14-14: Use of configuration import looks consistent.
Your import statement for envConfig fits the coding pattern seen elsewhere.


252-257: Validate argument ranges to avoid negative or excessively large multipliers.
While this dynamic complexity calculation is effective, ensure that args.first or args.last undergo validation to prevent unexpected negative or excessively large numbers, which might inflate or undercount complexity.

Would you like a script to verify or check for potential negative argument values across your resolvers?


261-267: Fixed complexity cost for edgesField is acceptable.
This looks good for controlling complexity.


271-277: Fixed complexity cost for nodeField is acceptable.
Similarly, this is consistent and helps standardize complexity allocation.

src/routes/graphql.ts (4)

1-1: Importing complexityFromQuery is well-aligned with the new complexity-based limits.
No issues detected.


12-12: Importing your leakyBucket utility is clear and consistent.
This ties your new rate-limiting feature into the GraphQL route.


91-91: Awaiting plugin registration ensures proper initialization.
Using await for mercuriusUpload prevents race conditions.


114-114: Disabling cache for Mercurius is valid but may affect performance.
If caching was previously beneficial, ensure the new setting aligns with system performance goals.

Copy link

@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.

Actionable comments posted: 0

🧹 Nitpick comments (2)
src/routes/graphql.ts (1)

218-218: Remove or enhance debug logging.

The console.log statement for complexity should be removed or replaced with proper structured logging using the application's logger.

-console.log("Complexity: ", complexity.complexity);
+fastify.log.debug({ complexity: complexity.complexity }, "Query complexity calculated");
src/envConfigSchema.ts (1)

244-258: Use JSDoc comments consistently for environment variables.

The GraphQL complexity field cost variables use single-line comments instead of the JSDoc format used elsewhere in the file. This inconsistency makes the documentation less standardized and potentially less useful for developers.

-//  cost of scalar field
+/**
+ * Cost of scalar field for GraphQL complexity calculation.
+ */
API_GRAPHQL_SCALAR_FIELD_COST: Type.Number({
  minimum: 0,
}),

-// cost of object field
+/**
+ * Cost of object field for GraphQL complexity calculation.
+ */
API_GRAPHQL_OBJECT_FIELD_COST: Type.Number({
  minimum: 0,
}),

-// cost of list field
+/**
+ * Cost of list field for GraphQL complexity calculation.
+ */
API_GRAPHQL_LIST_FIELD_COST: Type.Number({
  minimum: 0,
}),

-// base cost of mutation
+/**
+ * Base cost of mutation operations for GraphQL complexity calculation.
+ */
API_GRAPHQL_MUTATION_BASE_COST: Type.Number({
  minimum: 0,
}),
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6670799 and e682237.

📒 Files selected for processing (4)
  • envFiles/.env.ci (2 hunks)
  • envFiles/.env.devcontainer (2 hunks)
  • src/envConfigSchema.ts (1 hunks)
  • src/routes/graphql.ts (6 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • envFiles/.env.devcontainer
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Analyse Code With CodeQL (typescript)
🔇 Additional comments (4)
envFiles/.env.ci (1)

88-88: Fix typo in environment variable name.

The environment variable for bucket capacity has a typo:

-API_RATE_LIMIT_BUCKET_CAPACITY=100  
+API_RATE_LIMIT_BUCKET_CAPACITY=100

This appears to be the same issue mentioned in previous reviews.

src/routes/graphql.ts (3)

108-110: Storing request in fastify.currentRequest may lead to concurrency pitfalls.

Storing the current request in a global fastify property could cause race conditions under high traffic conditions as multiple requests might overwrite each other.

Consider using Fastify's built-in request context or passing the request object through the GraphQL context instead.


221-223: Enhance error response for rate limiting.

Instead of throwing a generic error, use a more descriptive error with proper HTTP status code and additional information about the rate limit.

-throw new Error("Too many requests");
+throw new Error(JSON.stringify({
+  statusCode: 429,
+  error: "Too Many Requests",
+  message: "Rate limit exceeded. Please try again later.",
+  complexity: complexity.complexity,
+  capacity: fastify.envConfig.API_RATE_LIMIT_BUCKET_CAPACITY
+}));

173-175:

❓ Verification inconclusive

Verify IP address availability to avoid unexpected errors.

The IP address retrieval uses an optional chaining operator but then immediately throws an error if the IP is not available at line 197. Consider a more graceful fallback mechanism for cases where the IP might not be available.


🏁 Script executed:

#!/bin/bash
# Check how the application handles requests without IP addresses
rg -A 2 "request\.ip" --type ts

Length of output: 33


Review Action Required: Confirm and Address Fallback Handling for Missing IP

It appears that the code retrieves the client’s IP address using optional chaining at lines 173–175. However, subsequent code (specifically around line 197) assumes that the IP is present and may throw an error if it’s undefined. Since our initial search didn’t reveal explicit handling code or alternative logic for absent IPs, please manually verify that the error thrown (or any unexpected behavior) is intentional and that graceful degradation isn’t needed.

  • Verify: Confirm if the absence of a valid IP is handled elsewhere or if a fallback (e.g., a default value or conditional check) should be introduced to prevent runtime errors.
  • Action: If no handling exists, consider implementing a fallback mechanism to ensure the application remains robust when the IP is unavailable.

Copy link

@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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
compose.yaml (1)

237-253: Addition of the Redis Service Configuration
The Redis service is well-configured using the redis:8.0-M02-alpine image. It includes a healthcheck (using redis-cli ping), is attached to the correct network, has a restart policy set to unless-stopped, and mounts a persistent volume redis_data.
Consider verifying that the specified healthcheck command returns the expected results in all environments.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e682237 and 2401a80.

📒 Files selected for processing (1)
  • compose.yaml (5 hunks)
🧰 Additional context used
🪛 YAMLlint (1.35.1)
compose.yaml

[error] 260-260: no new line character at the end of file

(new-line-at-end-of-file)

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Run tests for talawa api
  • GitHub Check: Analyse Code With CodeQL (typescript)
🔇 Additional comments (4)
compose.yaml (4)

3-7: Addition of Redis Network in the Networks Section
The new redis: network is added alongside the other networks. This provides proper isolation and connectivity for the Redis service.


33-36: Proper Dependency Configuration for Redis in the API Service
The depends_on block now includes Redis with a service_healthy condition and a comment explaining the fallback for third-party Redis services. This ensures that the API service waits for Redis to be healthy before starting.


74-80: Inclusion of New Environment Variables
New environment variables for Redis connectivity (API_REDIS_HOST and API_REDIS_PORT) as well as for GraphQL complexity and rate limiting settings have been added. They include mandatory error checking, which is a good practice for configuration validation.


105-105: API Service Network Update
The API service now lists redis among its networks, ensuring that it can connect to the newly defined Redis service.

Copy link

codecov bot commented Mar 12, 2025

Codecov Report

Attention: Patch coverage is 87.25490% with 26 lines in your changes missing coverage. Please review.

Project coverage is 52.79%. Comparing base (a1d2b15) to head (bc31741).
Report is 1 commits behind head on develop-postgres.

Files with missing lines Patch % Lines
src/routes/graphql.ts 77.61% 15 Missing ⚠️
src/utilities/leakyBucket.ts 85.00% 6 Missing ⚠️
src/graphql/types/User/organizationsWhereMember.ts 85.71% 5 Missing ⚠️
Additional details and impacted files
@@                 Coverage Diff                  @@
##           develop-postgres    #3359      +/-   ##
====================================================
+ Coverage             52.61%   52.79%   +0.18%     
====================================================
  Files                   467      469       +2     
  Lines                 35092    35285     +193     
  Branches               1207     1222      +15     
====================================================
+ Hits                  18462    18629     +167     
- Misses                16628    16654      +26     
  Partials                  2        2              

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

🚀 New features to boost your workflow:
  • Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@im-vedant
Copy link
Author

@palisadoes Please review.
I need to add a cost to each field except scalar fields. Once the main logic is reviewed, I will proceed with adding costs to all fields. For now, I have added costs to some fields for testing rate limiting. You can refer this doc for implementation details.

Copy link

@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.

Actionable comments posted: 1

♻️ Duplicate comments (1)
src/routes/graphql.ts (1)

212-217: 🛠️ Refactor suggestion

Error handling for rate limiting

The error handling for rate limit exceedance uses a basic Error object with a generic message. This should be replaced with a more structured error response.

 // If the request exceeds rate limits, reject it
 if (!isRequestAllowed) {
-  throw new Error("Too many requests");
+  throw new mercurius.ErrorWithProps("Too many requests", {
+    code: "RATE_LIMIT_EXCEEDED",
+    statusCode: 429,
+    complexity: complexity.complexity,
+    limit: fastify.envConfig.API_RATE_LIMIT_BUCKET_CAPACITY
+  });
 }

This provides more context about the rate limiting error and follows HTTP standards by using status code 429 for rate limiting errors.

🧹 Nitpick comments (3)
src/routes/graphql.ts (3)

204-211: Leaky bucket implementation and debug logging

The leaky bucket algorithm is correctly applied with configurable capacity and refill rate. However, there's a debug console log statement that should be removed before deployment.

 const isRequestAllowed = await leakyBucket(
   fastify,
   key,
   fastify.envConfig.API_RATE_LIMIT_BUCKET_CAPACITY,
   fastify.envConfig.API_RATE_LIMIT_REFILL_RATE,
   complexity.complexity,
 );
-console.log("Complexity: ", complexity.complexity);

190-193: IP availability check could be more robust

The current IP check throws a generic error if IP is not available. A more descriptive error would be helpful for debugging.

 if (!ip) {
-  throw new Error("IP is not available");
+  throw new mercurius.ErrorWithProps("Client IP address could not be determined", {
+    code: "IP_UNAVAILABLE",
+    statusCode: 400,
+  });
 }

150-153: Ensure schema validity for complexity calculation

The complexity calculation assumes the schema is valid. It would be prudent to add a check to ensure the schema is available before calculating complexity.

 // Calculate the complexity of the incoming GraphQL query
+if (!schema) {
+  fastify.log.error("Schema not available for complexity calculation");
+  throw new Error("Internal server error");
+}
 const complexity = complexityFromQuery(document.__currentQuery, {
   schema: schema,
   variables: variables,
 });
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d24dd55 and f5a4c7f.

📒 Files selected for processing (2)
  • src/createServer.ts (2 hunks)
  • src/routes/graphql.ts (6 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Run tests for talawa api
  • GitHub Check: Analyse Code With CodeQL (typescript)
🔇 Additional comments (6)
src/createServer.ts (1)

5-5: Import of Redis fastify plugin added

The inclusion of fastifyRedis is crucial for the rate limiting implementation mentioned in the PR objectives. This plugin allows Fastify to connect to Redis, which will be used to implement the Leaky Bucket algorithm.

src/routes/graphql.ts (5)

1-1: New complexity and rate limiting imports

The imports of complexityFromQuery and leakyBucket are essential for implementing the rate limiting system described in the PR objectives. The complexity plugin will help calculate query costs, while the leaky bucket algorithm will enforce the rate limits.

Also applies to: 12-12


91-91: Asynchronous plugin registration

Good use of await for plugin registration. This ensures that both mercuriusUpload and mercurius are fully registered before continuing, preventing potential race conditions.

Also applies to: 110-110


121-121: GraphQL response caching disabled

Setting cache: false disables the built-in caching for GraphQL responses. This is appropriate for a system with rate limiting, as it ensures fresh responses and accurate accounting of request complexity.


146-169: Query complexity calculation and operation type handling

The implementation correctly calculates query complexity using the Pothos Complexity Plugin and adjusts costs based on operation type. Adding a base cost for mutations is a good practice since they typically consume more resources.


171-203: Rate limit key generation based on authentication status

The code appropriately differentiates between authenticated and unauthenticated users for rate limiting. Using both user ID and IP for authenticated users prevents account sharing, which is a good security practice.

Copy link

@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.

Actionable comments posted: 1

🧹 Nitpick comments (4)
src/utilities/TalawaGraphQLError.ts (1)

201-203: Add JSDoc documentation for consistency

The new TooManyRequestsExtensions type lacks JSDoc documentation with examples, which breaks the consistency pattern established for other error types in this file.

Add documentation similar to other error types:

+/**
+ * When the client exceeds the rate limit for API requests.
+ *
+ * @example
+ * throw new TalawaGraphQLError({
+ * 	extensions: {
+ * 		code: "too_many_requests",
+ * 	},
+ * });
+ */
export type TooManyRequestsExtensions = {
	code: "too_many_requests";
};
src/routes/graphql.ts (3)

122-122: Consider documenting the cache configuration change

Disabling the cache is a significant change that could affect performance. It's likely necessary for the rate limiting implementation but should be documented.

Add a comment explaining why cache is disabled:

-		cache: false,
+		// Disable cache to ensure rate limiting is applied to all requests
+		cache: false,

212-212: Remove debug logging in production code

Console.log statements should be removed before merging to production.

-console.log("Complexity: ", complexity.complexity);

147-221: Consider refactoring the preExecution hook for better maintainability

The preExecution hook handles multiple responsibilities: complexity calculation, authentication, and rate limiting. Consider refactoring this into smaller, focused functions for better maintainability.

Extract logic into separate functions:

fastify.graphql.addHook(
	"preExecution",
	async (schema, context, document, variables) => {
-		// Calculate the complexity of the incoming GraphQL query
-		const complexity = complexityFromQuery(document.__currentQuery, {
-			schema: schema,
-			variables: variables,
-		});
-		const request = document.reply.request;
-
-		// Find the operation definition node to determine if this is a query, mutation, or subscription
-		const operationDefinition = context.definitions.find(
-			(definition) => definition.kind === "OperationDefinition",
-		);
-		const operationType = operationDefinition
-			? operationDefinition.operation
-			: undefined;
-
-		// Mutations typically have a higher base cost than queries
-		// Add the configured base cost for mutations to increase their complexity score
-		if (operationType === "mutation") {
-			complexity.complexity +=
-				fastify.envConfig.API_GRAPHQL_MUTATION_BASE_COST;
-		}
+		const request = document.reply.request;
+		const complexity = calculateQueryComplexity(schema, document, variables, context, fastify);
+		const currentClient = await authenticateClient(request);
+		const rateLimitKey = generateRateLimitKey(request.ip, currentClient);
+		await enforceRateLimit(fastify, rateLimitKey, complexity.complexity);
+	},
+);
+
+/**
+ * Calculates the complexity of a GraphQL query
+ */
+function calculateQueryComplexity(schema, document, variables, context, fastify) {
+	const complexity = complexityFromQuery(document.__currentQuery, {
+		schema: schema,
+		variables: variables,
+	});
+	
+	// Find the operation definition node to determine if this is a query, mutation, or subscription
+	const operationDefinition = context.definitions.find(
+		(definition) => definition.kind === "OperationDefinition",
+	);
+	const operationType = operationDefinition
+		? operationDefinition.operation
+		: undefined;
+	
+	// Mutations typically have a higher base cost than queries
+	if (operationType === "mutation") {
+		complexity.complexity += fastify.envConfig.API_GRAPHQL_MUTATION_BASE_COST;
+	}
+	
+	return complexity;
+}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f5a4c7f and 1f7e375.

📒 Files selected for processing (2)
  • src/routes/graphql.ts (6 hunks)
  • src/utilities/TalawaGraphQLError.ts (3 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Run tests for talawa api
  • GitHub Check: Analyse Code With CodeQL (typescript)
🔇 Additional comments (7)
src/utilities/TalawaGraphQLError.ts (2)

213-214: LGTM! Union type properly updated

The TooManyRequestsExtensions type is correctly added to the TalawaGraphQLErrorExtensions union type.


232-232: LGTM! Error message properly defined

The error message for the "too_many_requests" code is clear and follows the established pattern.

src/routes/graphql.ts (5)

1-1: LGTM! Proper import for complexity calculation

The complexityFromQuery import is correctly added to support the query complexity calculation for rate limiting.


12-13: LGTM! Required imports for rate limiting

The imports for TalawaGraphQLError and leakyBucket are correctly added to support the rate limiting implementation.


92-92: LGTM! Proper async registration

Adding await ensures the plugin is fully registered before continuing, preventing potential race conditions.


111-111: LGTM! Proper async registration

Adding await ensures the plugin is fully registered before continuing, preventing potential race conditions.


215-219: LGTM! Proper rate limit error handling

Using the custom TalawaGraphQLError with the "too_many_requests" code is the correct approach for rate limiting errors.

Copy link

@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.

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/routes/graphql.ts (1)

217-217: Remove console.log statement before deployment

Console.log statements should not be present in production code as they can expose sensitive information and impact performance.

- console.log("Complexity: ", complexity.complexity);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1f7e375 and 30831b2.

📒 Files selected for processing (2)
  • src/createServer.ts (2 hunks)
  • src/routes/graphql.ts (6 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/createServer.ts
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Run tests for talawa api
  • GitHub Check: Analyse Code With CodeQL (typescript)
🔇 Additional comments (7)
src/routes/graphql.ts (7)

92-92: Appropriate use of await with plugin registrations

Adding await to the fastify.register() calls ensures that plugins are registered sequentially, preventing potential race conditions if there are dependencies between plugins.

Also applies to: 111-111


147-226: Well-implemented rate limiting with the leaky bucket algorithm

The preExecution hook implements a robust rate limiting solution that:

  1. Calculates query complexity using the Pothos plugin
  2. Applies different costs based on operation type (mutation vs query)
  3. Uses different rate limit keys for authenticated vs unauthenticated users
  4. Properly handles error cases with structured TalawaGraphQLError objects

The implementation addresses previous review comments regarding error handling structure.


191-198: Structured error handling properly implemented

The error handling for missing IP addresses now correctly uses TalawaGraphQLError with appropriate extensions and message, which resolves the previous review comment about consistent error handling.


220-224: Rate limit error properly structured

The error thrown when rate limits are exceeded uses the appropriate TalawaGraphQLError structure with the "too_many_requests" code, which addresses previous feedback about error handling consistency.


122-122:

❓ Verification inconclusive

Verify the impact of disabling GraphQL caching

Setting cache: false disables GraphQL response caching, which is appropriate for rate-limited APIs where each request should be evaluated independently. However, this might impact performance for frequently executed identical queries.


🏁 Script executed:

#!/bin/bash
# Check if there are any tests that depend on GraphQL caching behavior
rg -l "cache.*graphql|graphql.*cache" --type-add "test:*.test.*" --type test

Length of output: 78


Action Required: Manually Verify Impact on GraphQL Caching

The change disables caching via cache: false, which is appropriate for rate-limited APIs where independent evaluation is required. However, our automated search didn’t locate any tests that specifically reference or validate GraphQL caching behavior. Please verify manually that this change does not adversely affect performance for frequently executed identical queries. If applicable, consider adding tests to cover this behavior.


156-156:

❓ Verification inconclusive

Verify request access method in high concurrency scenarios

Accessing document.reply.request directly could potentially lead to the same concurrency issues mentioned in previous review comments about fastify.currentRequest. In high-load scenarios, ensure that each request is properly isolated.


🏁 Script executed:

#!/bin/bash
# Look for any tests that test concurrent GraphQL requests
rg -A 5 -B 5 "concurrent.*request|simultaneous.*request|parallel.*request" --type-add "test:*.test.*" --type test

Length of output: 115


Concurrency Verification Action: Validate Concurrent Access Behavior

In src/routes/graphql.ts (line 156), the code directly accesses document.reply.request. This pattern raises concerns about potential concurrency issues similar to those previously noted with fastify.currentRequest. The search for tests simulating concurrent GraphQL requests returned no output, so it's unclear whether the current isolation strategy is adequate.

  • Action Required: Please manually verify—ideally with load tests or by augmenting the test suite—that concurrent GraphQL requests remain properly isolated.
  • Recommendation: If the current approach is confirmed to be safe, document the isolation mechanism in the code to clarify its concurrency protection.

211-215:

❓ Verification inconclusive

Verify environment variable configuration

Ensure that the environment variables for rate limiting are properly configured in all deployment environments:

  • API_RATE_LIMIT_BUCKET_CAPACITY
  • API_RATE_LIMIT_REFILL_RATE
  • API_GRAPHQL_MUTATION_BASE_COST

🌐 Web query:

What are typical values for leaky bucket rate limiting configuration in GraphQL APIs?

💡 Result:

Shopify's GraphQL API employs a leaky bucket algorithm for rate limiting, with configurations varying by plan tier. Here's a breakdown of typical values:

Rate Limit Configuration by Plan

  • Standard Plan:

    • Bucket Size: 1,000 cost points
    • Leak Rate: 50 points per second
    • Example: A simple query costing 1 point allows ~50 requests/sec sustained, with bursts up to 1,000 points.
  • Advanced Plan:

    • Bucket Size: 4,000 cost points
    • Leak Rate: 100 points per second
    • Enables larger bursts (4,000 points) and higher sustained throughput.
  • Shopify Plus:

    • Bucket Size: 20,000 cost points
    • Leak Rate: 1,000 points per second
    • Supports enterprise-scale operations with significant burst capacity.

Key Implementation Details

  • Query Cost Calculation:
    Simple queries (e.g., fetching basic product data) typically cost 1 point, while mutations or complex nested queries can cost 10+ points[1][4][10].
  • Bulk Operations:
    Exempt from standard rate limits, allowing large dataset processing without impacting the leaky bucket quota[10].
  • Monitoring:
    Responses include headers like X-Shopify-Shop-Api-Call-Limit to track usage against limits[3][14].

Comparison to REST API

While Shopify's REST API uses request-count limits (40 requests/bucket, leaking 2/sec for standard plans), GraphQL's point-based system provides more flexibility. For example, 50 simple GraphQL queries/sec are permitted under standard plans vs. 2 REST requests/sec[3][10].

Developers should optimize queries using tools like Shopify's GraphiQL IDE to estimate costs and leverage bulk operations for large datasets[1][10].

Citations:


Action: Verify and Adjust GraphQL Rate Limiting Configurations

Ensure that the environment variables used for rate limiting are properly set for all deployments. In particular, please verify:

  • API_RATE_LIMIT_BUCKET_CAPACITY
    Typical configurations (e.g., for a Standard Plan) might use a bucket size around 1,000 cost points, with higher values (like 4,000 or 20,000) possibly needed in advanced or enterprise scenarios.

  • API_RATE_LIMIT_REFILL_RATE
    A common refill rate is approximately 50 points per second under standard conditions, though this should be adjusted based on expected load.

  • API_GRAPHQL_MUTATION_BASE_COST
    Confirm that this variable is defined and tuned to reflect the cost of mutation operations, ensuring that mutation requests are adequately rate limited even though it doesn’t appear in the snippet shown.

These recommendations are in line with typical leaky bucket implementations seen in GraphQL APIs, such as Shopify’s configuration. Please review your environment configurations (in all deployment environments) to ensure they meet your API’s throughput and mutation cost requirements.

Copy link
Contributor

@palisadoes palisadoes left a comment

Choose a reason for hiding this comment

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

  1. You need to make sure this applies to these files you missed.
    1. docker/compose.deploy.yaml
    2. docker/compose.testing.yaml
    3. .env.deploy
    4. .env.production
  2. You need to update the environment variable markdown page with your new entries and an explanation of what they mean.

Copy link

@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.

Actionable comments posted: 1

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 30831b2 and dd4300c.

📒 Files selected for processing (3)
  • docker/compose.deploy.yaml (5 hunks)
  • envFiles/.env.deploy (2 hunks)
  • envFiles/.env.production (2 hunks)
🧰 Additional context used
🪛 YAMLlint (1.35.1)
docker/compose.deploy.yaml

[error] 262-262: no new line character at the end of file

(new-line-at-end-of-file)

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Run tests for talawa api
  • GitHub Check: Analyse Code With CodeQL (typescript)
🔇 Additional comments (13)
docker/compose.deploy.yaml (5)

7-7: Define the Redis network.
The new redis: network is added to the networks block to support the Redis service. Ensure that this network name is consistently used across all configurations.


33-36: Add Redis dependency to the API service.
The depends_on block now includes a Redis service with a health check condition and required: false. Verify that marking it as not strictly required aligns with your deployment strategy—this can be useful when using third-party Redis services.


74-81: Integrate Redis and GraphQL rate limiting environment variables.
New environment variables for Redis connection (API_REDIS_HOST, API_REDIS_PORT) as well as GraphQL field cost and rate limiting parameters have been added. Ensure these values remain in sync with your application’s settings and are documented in the corresponding environment files.


105-105: Connect the API service to the Redis network.
The addition of - redis in the API service’s network list ensures connectivity to the new Redis network. This change is crucial for internal service communication.


240-256: Introduce the Redis service configuration.
A complete Redis service has been added with the redis:8.0-M02-alpine image, a defined healthcheck, network association, restart policy, and persistent volume mapping. Verify that the chosen image tag meets your production stability and security requirements.

envFiles/.env.deploy (4)

47-48: Set Redis connection details.
The environment variables API_REDIS_HOST=redis and API_REDIS_PORT=6379 are introduced. These values should match the service name and port as defined in your Docker Compose configuration.


89-95: Define GraphQL field cost defaults.
A new section for GraphQL field costs (scalar, object, list, and mutation base costs) has been added. Confirm that these baseline values adhere to your cost calculation logic in the GraphQL layer.


96-100: Set rate limiting parameters.
The variables API_RATE_LIMIT_BUCKET_CAPACITY and API_RATE_LIMIT_REFILL_RATE are added to configure the leaky bucket algorithm. Verify these values provide the intended request throttling under expected API loads.


101-103: Configure Redis exposure via Docker Compose.
Introducing REDIS_MAPPED_HOST_IP and REDIS_MAPPED_PORT helps map Redis for external accessibility if required. Ensure these settings are consistent with your overall networking plan.

envFiles/.env.production (4)

37-38: Set production Redis connection variables.
The production file now includes API_REDIS_HOST=redis and API_REDIS_PORT=6379. Ensure these values correctly point to your Redis instance within the production environment.


76-80: Define production GraphQL base field costs.
The section for GraphQL field costs has been added with default values. Confirm that these costs align with your complexity calculations and are documented appropriately for production troubleshooting.


81-83: Configure production rate limiting settings.
The variables API_RATE_LIMIT_BUCKET_CAPACITY and API_RATE_LIMIT_REFILL_RATE are now defined for the production environment. Review these values to ensure they provide effective rate limiting under production traffic conditions.


84-86: Declare Redis Docker container access settings for production.
The added REDIS_MAPPED_HOST_IP=127.0.0.1 and REDIS_MAPPED_PORT=6379 enable production-level connectivity to the Redis service via Docker Compose. Ensure these match your network configurations and any firewall settings in production.

Copy link

@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.

Actionable comments posted: 6

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dd4300c and dfb6f84.

📒 Files selected for processing (8)
  • compose.yaml (5 hunks)
  • docker/compose.deploy.yaml (5 hunks)
  • docker/compose.devcontainer.yaml (1 hunks)
  • docker/compose.testing.yaml (1 hunks)
  • envFiles/.env.ci (2 hunks)
  • envFiles/.env.deploy (2 hunks)
  • envFiles/.env.devcontainer (2 hunks)
  • envFiles/.env.production (2 hunks)
🧰 Additional context used
🪛 YAMLlint (1.35.1)
compose.yaml

[error] 262-262: no new line character at the end of file

(new-line-at-end-of-file)

docker/compose.testing.yaml

[error] 105-105: trailing spaces

(trailing-spaces)


[error] 119-119: no new line character at the end of file

(new-line-at-end-of-file)

docker/compose.deploy.yaml

[error] 264-264: no new line character at the end of file

(new-line-at-end-of-file)

docker/compose.devcontainer.yaml

[error] 166-166: wrong indentation: expected 6 but found 4

(indentation)


[warning] 170-170: comment not indented like content

(comments-indentation)


[error] 173-173: wrong indentation: expected 6 but found 4

(indentation)


[error] 190-190: trailing spaces

(trailing-spaces)


[error] 192-192: too many blank lines

(2 > 0) (empty-lines)

🪛 GitHub Actions: Pull request workflow
docker/compose.testing.yaml

[error] 1-1: Validation error: Additional property health-check is not allowed.

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Analyse Code With CodeQL (typescript)
🔇 Additional comments (21)
compose.yaml (4)

7-7: Approval: New 'redis' network added.
The addition of the redis network is consistent with the updated Redis service configuration.


33-36: Approval: 'redis' dependency added to the API service.
Including the Redis service in the depends_on section with a health condition is correctly configured.


74-81: Approval: Environment variables for Redis and GraphQL complexities updated.
The new entries (e.g., API_REDIS_HOST, API_REDIS_PORT, and the GraphQL cost variables) are clearly defined and align with the new Redis and rate limiting functionality.


261-262: Duplicate: Add newline at the end of the file for volume configuration.
A newline is needed at the end of the file to comply with YAML linting standards.

🧰 Tools
🪛 YAMLlint (1.35.1)

[error] 262-262: no new line character at the end of file

(new-line-at-end-of-file)

envFiles/.env.ci (3)

39-40: Approval: Redis configuration added.
The variables API_REDIS_HOST=redis and API_REDIS_PORT=6379 are correctly set to integrate Redis into the API.


76-76: Approval: COMPOSE_PROFILES updated to include redis_test.
This update ensures that the Redis test service is activated in the CI environment.


79-90: Approval: GraphQL and Rate Limiting variables are properly defined.
The settings for GraphQL field costs and rate limiting (e.g., API_RATE_LIMIT_BUCKET_CAPACITY and API_RATE_LIMIT_REFILL_RATE) are clearly established.

docker/compose.deploy.yaml (2)

240-258: Approval: Redis service configuration verified.
The Redis service is properly defined using the redis:8.0-M02-alpine image along with a correct healthcheck, networking, and volume configuration.


264-264: Duplicate: Ensure a newline at the end of the file.
Adding a newline after the volumes block will bring the file into compliance with YAMLlint requirements.

🧰 Tools
🪛 YAMLlint (1.35.1)

[error] 264-264: no new line character at the end of file

(new-line-at-end-of-file)

envFiles/.env.devcontainer (4)

41-42: Approval: Redis configuration is correctly added.
The declarations for API_REDIS_HOST and API_REDIS_PORT are appropriately set for the dev environment.


106-106: Approval: COMPOSE_PROFILES updated for the dev environment.
Including redis_test in COMPOSE_PROFILES ensures that the Redis test service is part of the development setup.


118-119: Request: Verify rate limiting values for the dev environment.
The values for API_RATE_LIMIT_BUCKET_CAPACITY (100) and API_RATE_LIMIT_REFILL_RATE (10) differ significantly from the CI environment. Please confirm that these lower values are intentional for development purposes.


122-123: Approval: Redis container service mapping is properly defined.
The variables REDIS_MAPPED_HOST_IP and REDIS_MAPPED_PORT are configured correctly for the local development environment.

envFiles/.env.production (4)

37-38: Added Redis Configuration Variables
New environment variables API_REDIS_HOST=redis and API_REDIS_PORT=6379 have been introduced. The naming and values are consistent with the updated Docker Compose configurations.


74-76: Updated Compose Profiles
The COMPOSE_PROFILES variable has been updated (e.g. COMPOSE_PROFILES=api,caddy,minio,postgres,redis) to include the new redis service. This change ensures that the Redis container is correctly part of the deployment stack.


77-88: GraphQL Costs and Rate Limiting Variables Added
The addition of environment variables for GraphQL cost settings (API_GRAPHQL_SCALAR_FIELD_COST, API_GRAPHQL_OBJECT_FIELD_COST, API_GRAPHQL_LIST_FIELD_COST, and API_GRAPHQL_MUTATION_BASE_COST) as well as for rate limiting (API_RATE_LIMIT_BUCKET_CAPACITY, API_RATE_LIMIT_REFILL_RATE) is clear and consistent. Please verify that these default values align with your query budgeting strategy across environments.


89-91: Redis Service Mapping for Docker Compose
The newly added Redis service mapping variables (REDIS_MAPPED_HOST_IP=127.0.0.1 and REDIS_MAPPED_PORT=6379) are correctly placed at the end of the file. This ensures consistency with the configurations in the Docker Compose files.

envFiles/.env.deploy (4)

47-48: Redis Environment Variables for Deployment
The deployment environment now includes API_REDIS_HOST=redis and API_REDIS_PORT=6379, aligning with the production settings. This consistency helps ensure that Redis connectivity works as expected in different environments.


86-88: Compose Profiles Update in Deployment
The COMPOSE_PROFILES variable (line 86) is updated to include redis (i.e. COMPOSE_PROFILES=api,caddy,minio,postgres,redis), ensuring that the Redis service is launched as part of the deployment stack.


89-100: GraphQL and Rate Limiting Configurations for Deployment
New environment variables defining GraphQL field costs and rate limiting settings have been added (lines 89–100). These variables mirror those in the production configuration, which is good for consistency. Please verify that the default values for these settings meet the desired operational criteria for the API under load.


101-103: Redis Compose Service Configuration in Deployment
The final block correctly maps the Docker Compose settings for Redis with REDIS_MAPPED_HOST_IP=127.0.0.1 and REDIS_MAPPED_PORT=6379. This ensures that the service configuration in deployment matches the settings in other environments.

Copy link

@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.

Actionable comments posted: 2

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c3310a0 and bcae025.

📒 Files selected for processing (2)
  • docker/compose.devcontainer.yaml (1 hunks)
  • docker/compose.testing.yaml (1 hunks)
🧰 Additional context used
🪛 YAMLlint (1.35.1)
docker/compose.testing.yaml

[error] 118-118: no new line character at the end of file

(new-line-at-end-of-file)

docker/compose.devcontainer.yaml

[warning] 170-170: comment not indented like content

(comments-indentation)


[error] 188-188: no new line character at the end of file

(new-line-at-end-of-file)

🔇 Additional comments (2)
docker/compose.testing.yaml (1)

105-118:

❓ Verification inconclusive

New Redis-Test Service Configuration Review

The new redis-test service block is implemented with the expected keys (image, healthcheck, networks, restart, and profiles) using the Redis image redis:8.0-M02-alpine. However, please verify that the network "redis_test" used on line 115 is explicitly defined in the networks section (currently only minio_test and postgres_test exist). If not defined elsewhere, consider adding it at the top-level to avoid potential network misconfigurations.

Additionally, static analysis has flagged that there is no newline at the end of the file (line 118). Please add a trailing newline to comply with YAML linting guidelines.


Attention: Verify Redis-Test Network and Trailing Newline Compliance

  • The redis-test service configuration in docker/compose.testing.yaml (lines 105–118) is correctly structured with the expected keys.
  • Action Required: Confirm that the network "redis_test" used on line 115 is explicitly declared in the top-level networks section. Currently, only minio_test and postgres_test appear; if "redis_test" isn’t defined elsewhere, please add it to avoid misconfiguration.
  • Action Required: Add a trailing newline at the end of the file (post line 118) to meet YAML linting guidelines.
🧰 Tools
🪛 YAMLlint (1.35.1)

[error] 118-118: no new line character at the end of file

(new-line-at-end-of-file)

docker/compose.devcontainer.yaml (1)

164-169: Redis Service Configuration Consistency

The newly added redis service (lines 164-169) correctly defines the ports for the Redis container using environment variables. The configuration appears consistent with similar services. Please double-check that using the same environment variable (${REDIS_MAPPED_HOST_IP}) for the host_ip is intentional and aligns with your overall deployment architecture.

Copy link

@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.

Actionable comments posted: 2

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bcae025 and 2c8fd82.

📒 Files selected for processing (4)
  • docker/compose.testing.yaml (4 hunks)
  • envFiles/.env.ci (2 hunks)
  • envFiles/.env.devcontainer (2 hunks)
  • test/envConfigSchema.ts (1 hunks)
🧰 Additional context used
🪛 YAMLlint (1.35.1)
docker/compose.testing.yaml

[error] 121-121: no new line character at the end of file

(new-line-at-end-of-file)

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Run tests for talawa api
  • GitHub Check: Analyse Code With CodeQL (typescript)
🔇 Additional comments (6)
envFiles/.env.ci (2)

89-90: Looks good - rate limiting configuration added correctly.

The rate limiting configuration with bucket capacity of 10000 and refill rate of 100 aligns well with the PR objective of implementing the Leaky Bucket Algorithm for rate limiting.


82-85: GraphQL field cost configuration looks good.

The GraphQL field costs are appropriately configured, with scalar fields having no cost (0), object and list fields having minimal cost (1), and mutations having a higher base cost (10). This supports the query cost calculation objective mentioned in the PR.

envFiles/.env.devcontainer (1)

119-120: Note different rate limit values in development vs CI environments.

The development environment uses significantly lower values (bucket capacity of 100, refill rate of 10) compared to the CI environment (bucket capacity of 10000, refill rate of 100). This is appropriate for development testing but ensure the production values are carefully considered.

test/envConfigSchema.ts (1)

17-17: LGTM - Redis test host property added correctly.

The Redis test host property has been properly added to the test environment config schema, following the same pattern used for other test properties.

docker/compose.testing.yaml (2)

29-29: Redis integration looks good.

The Redis test host environment variable and network configuration have been properly added to the API service.

Also applies to: 39-39


108-121:

✅ Verification successful

Verify Redis version compatibility.

The Redis service is using version 8.0-M02-alpine, which is a milestone (pre-release) version. Consider using a stable release for production environments.


🌐 Web query:

Is Redis 8.0-M02 a stable release for production use?

💡 Result:

Redis 8.0-M02 is not a stable release for production use. According to Redis' official release notes and documentation, milestone releases like 8.0-M02 are non-feature-complete pre-releases intended for testing and experimentation, with explicit warnings against production deployment[1][2][5].

Key details:

  1. Release status:

    • Classified as a milestone (pre-release) toward Redis 8.0 GA (General Availability), not a stable release[1][2].
    • Redis' policy states stable releases begin with RC1 (Release Candidate 1), which hasn't been reached yet for Redis 8.0[1][3].
  2. Limitations:

    • Untested upgrade paths for environments using modules like RediSearch or Redis Stack[1][12].
    • Missing features planned for the final 8.0 GA release[1][9].
  3. Security considerations:

    • Includes security fixes (e.g., CVE-2024-31449, CVE-2024-31227)[1][2][12], but the overall release hasn't undergone full stability validation for production workloads[3][6].

For production environments, Redis recommends using the latest stable version (7.2.6 as of March 2025)[1][3][6], while milestone releases like 8.0-M02 are best reserved for development/testing scenarios. The stable GA release of Redis 8.0 will follow once feature completeness and rigorous testing are achieved[3][9].

Citations:


Redis Version Compatibility – Use Stable Releases for Production

We verified that Redis 8.0-M02 is indeed a milestone pre-release and is not considered production-ready. Since the docker/compose.testing.yaml file is used for testing, using this version might be acceptable for experimental purposes. However, if this configuration is ever intended for production use, please update the Redis image to a stable release (for example, redis:7.2.6 or the current stable version).

  • Location: docker/compose.testing.yaml, lines 108-121
  • Action: Ensure that production deployments do not use the pre-release Redis version.
🧰 Tools
🪛 YAMLlint (1.35.1)

[error] 121-121: no new line character at the end of file

(new-line-at-end-of-file)

coderabbitai[bot]
coderabbitai bot previously approved these changes Mar 14, 2025
coderabbitai[bot]
coderabbitai bot previously approved these changes Mar 14, 2025
@im-vedant
Copy link
Author

@palisadoes Please see this comment. I have updated the docs and docker files. PTAL

@im-vedant im-vedant requested a review from palisadoes March 14, 2025 18:16
Copy link

@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.

Actionable comments posted: 1

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d589a87 and 7e6959e.

📒 Files selected for processing (1)
  • src/graphql/types/User/organizationsWhereMember.ts (2 hunks)
🧰 Additional context used
🪛 GitHub Actions: Pull request workflow
src/graphql/types/User/organizationsWhereMember.ts

[error] 238-274: Formatter would have printed the following content: The formatting issues need to be resolved.

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Analyse Code With CodeQL (typescript)
🔇 Additional comments (2)
src/graphql/types/User/organizationsWhereMember.ts (2)

19-19: Good addition of the GraphQL complexity configuration import.

The import of envConfig from the graphQL limits utility is appropriate for implementing the complexity calculations needed for rate limiting.


246-251: Well-implemented complexity function.

The complexity calculation is properly implemented, using the environment-configured field cost with a dynamic multiplier based on the requested items count. This is a good approach for rate limiting as it scales the cost based on the amount of data requested.

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
coderabbitai[bot]
coderabbitai bot previously approved these changes Mar 14, 2025
@Cioppolo14 Cioppolo14 removed the request for review from palisadoes March 15, 2025 12:22
@Cioppolo14 Cioppolo14 added the ignore-sensitive-files-pr The contributor has a legitimate reason for editiing protected files label Mar 15, 2025
@im-vedant im-vedant requested a review from palisadoes March 15, 2025 17:36
@palisadoes palisadoes merged commit a6c9fd8 into PalisadoesFoundation:develop-postgres Mar 15, 2025
16 of 17 checks passed
@im-vedant
Copy link
Author

@palisadoes I need to add a cost to each field except scalar fields. In this PR, I have added costs to some fields for testing rate limiting. I will raise another PR in which I will assign cost to all the remaining fields.

@palisadoes
Copy link
Contributor

OK

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ignore-sensitive-files-pr The contributor has a legitimate reason for editiing protected files
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants