Skip to content

Conversation

@Moumouls
Copy link
Member

@Moumouls Moumouls commented Nov 10, 2025

Pull Request

Issue

Underload, apollo server can be initialized multiple times. Schema ref should be used as mutex to prevent parallel init, so all _getServer await the same promise ref

Closes: FILL_THIS_OUT

Approach

Using schema as a ref mutex

Tasks

  • Add tests
  • Add changes to documentation (guides, repository pages, code comments)
  • Add security check
  • Add new Parse Error codes to Parse JS SDK

Summary by CodeRabbit

  • Bug Fixes

    • Improved concurrent initialization so parallel requests reuse the same server instance, preventing duplicate server creation during simultaneous access.
  • Tests

    • Added a test that verifies repeated parallel calls to server initialization return the same shared server reference.

@parse-github-assistant
Copy link

I will reformat the title to use the proper commit message syntax.

@parse-github-assistant parse-github-assistant bot changed the title fix: apollo parallel server init under load fix: Apollo parallel server init under load Nov 10, 2025
@parse-github-assistant
Copy link

parse-github-assistant bot commented Nov 10, 2025

🚀 Thanks for opening this pull request!

❌ Please fill out all fields with a placeholder FILL_THIS_OUT. If a field does not apply to the pull request, fill in n/a or delete the line.

@coderabbitai
Copy link

coderabbitai bot commented Nov 10, 2025

📝 Walkthrough

Walkthrough

Adds a concurrency guard and promise-based initialization to ParseGraphQLServer._getServer(), and a test that verifies 100 parallel _getServer() calls resolve to the same server reference.

Changes

Cohort / File(s) Summary
Test
spec/ParseGraphQLServer.spec.js
Adds a test that resets cached server, invokes _getServer() 100 times in parallel, awaits all results, and asserts every result is identical to the first.
Concurrency & Init Logic
src/GraphQL/ParseGraphQLServer.js
Introduces _schemaRefMutex checks and a createServer() factory. Stores a non-awaited server initialization promise in this._server so parallel callers share the same initialization promise; on error, resets _server and _schemaRefMutex.

Sequence Diagram(s)

sequenceDiagram
    participant CallerA
    participant CallerB
    participant ParseGraphQLServer
    participant Mutex
    participant ServerInit

    Note over CallerA,CallerB: Parallel callers request server
    CallerA->>ParseGraphQLServer: _getServer()
    CallerB->>ParseGraphQLServer: _getServer()
    ParseGraphQLServer->>Mutex: check/acquire _schemaRefMutex
    Mutex-->>ParseGraphQLServer: lock/allow creation OR attach to existing promise
    alt first creator
        ParseGraphQLServer->>ServerInit: createServer() (returns promise)
        ServerInit-->>ParseGraphQLServer: resolves with Server instance
        ParseGraphQLServer-->>CallerA: resolves with Server
        ParseGraphQLServer-->>CallerB: resolves with same Server (await same promise)
    else attaching caller
        ParseGraphQLServer-->>CallerB: returns existing init promise
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Areas to focus:
    • correctness of _schemaRefMutex acquisition/release and race conditions
    • storing non-awaited promise in this._server and its lifecycle (success, failure, retry)
    • error-handling path that resets _server and _schemaRefMutex
    • test robustness and potential flakiness under CI concurrency

Possibly related PRs

Suggested reviewers

  • mtrezza

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Description check ❓ Inconclusive The description is incomplete: it lacks a specific issue link (still shows FILL_THIS_OUT), and the Approach section is vague. However, the Issue explanation and technical details are provided. Link the PR to a specific GitHub issue and expand the Approach section with more detailed explanation of the mutex implementation using schema references.
✅ Passed checks (2 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Title check ✅ Passed The title accurately describes the main change: fixing a race condition where multiple Apollo server initializations can occur under load by implementing mutex-based synchronization.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@parseplatformorg
Copy link
Contributor

parseplatformorg commented Nov 10, 2025

Snyk checks have passed. No issues have been found so far.

Status Scanner Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@Moumouls
Copy link
Member Author

@Stovedal, thanks for your report, it could lead to a significant performance gain during startup under heavy load.

@Moumouls Moumouls requested a review from mtrezza November 10, 2025 17:30
@Moumouls Moumouls changed the title fix: Apollo parallel server init under load perf: Apollo parallel server init under load Nov 10, 2025
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)
spec/ParseGraphQLServer.spec.js (1)

121-134: Good concurrency test; tighten assertions and reset.

Looks solid and reflects the intended mutex behavior. Two nits:

  • Prefer a single assertion using a Set to ensure all references are identical.
  • If the implementation now stores the in-flight promise on _server, resetting server may not cold‑start the path. Consider clearing the correct slot (or adding a tiny helper) to avoid false positives.
-    it('should return same server reference when called 100 times in parallel', async () => {
-      parseGraphQLServer.server = undefined;
+    it('should return same server reference when called 100 times in parallel', async () => {
+      // Ensure cold start regardless of internal field name.
+      parseGraphQLServer.server = undefined;
+      if ('_server' in parseGraphQLServer) parseGraphQLServer._server = undefined;
@@
-      // All resolved servers should be the same reference
-      const firstServer = servers[0];
-      servers.forEach((server, index) => {
-        expect(server).toBe(firstServer);
-      });
+      // All resolved servers should be the same reference
+      const unique = new Set(servers);
+      expect(unique.size).toBe(1);
     });

If feasible, also spy on the underlying server factory to assert it runs once (e.g., spyOn(parseGraphQLServer, '_createServer') or equivalent) to make the test stricter. Based on learnings.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 133660f and ad81073.

📒 Files selected for processing (2)
  • spec/ParseGraphQLServer.spec.js (1 hunks)
  • src/GraphQL/ParseGraphQLServer.js (1 hunks)
🧰 Additional context used
🧠 Learnings (7)
📓 Common learnings
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 0
File: :0-0
Timestamp: 2025-11-08T13:46:04.940Z
Learning: When reviewing Parse Server PRs that add new features, always check whether the feature is documented in the README.md file, though for new Parse Server options this is optional rather than required.
📚 Learning: 2025-05-09T09:59:06.289Z
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 9445
File: spec/ParseLiveQuery.spec.js:1340-1375
Timestamp: 2025-05-09T09:59:06.289Z
Learning: Tests in the parse-server repository should use promise-based approaches rather than callback patterns with `done()`. Use a pattern where a Promise is created that resolves when the event occurs, then await that promise.

Applied to files:

  • spec/ParseGraphQLServer.spec.js
📚 Learning: 2025-05-04T20:41:05.147Z
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 9445
File: spec/ParseLiveQuery.spec.js:1312-1338
Timestamp: 2025-05-04T20:41:05.147Z
Learning: New tests in the parse-server repository should use async/await with promise-based patterns rather than callback patterns with `done()`.

Applied to files:

  • spec/ParseGraphQLServer.spec.js
📚 Learning: 2025-05-09T09:59:06.289Z
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 9445
File: spec/ParseLiveQuery.spec.js:1340-1375
Timestamp: 2025-05-09T09:59:06.289Z
Learning: New tests in the parse-server repository should use async/await with promise-based patterns rather than callback patterns with `done()`. The preferred pattern is to create a Promise that resolves when an expected event occurs, then await that Promise.

Applied to files:

  • spec/ParseGraphQLServer.spec.js
📚 Learning: 2025-04-30T19:31:35.344Z
Learnt from: RahulLanjewar93
Repo: parse-community/parse-server PR: 9744
File: spec/ParseLiveQuery.spec.js:0-0
Timestamp: 2025-04-30T19:31:35.344Z
Learning: In the Parse Server codebase, the functions in QueryTools.js are typically tested through end-to-end behavior tests rather than direct unit tests, even though the functions are exported from the module.

Applied to files:

  • spec/ParseGraphQLServer.spec.js
📚 Learning: 2025-10-16T19:27:05.311Z
Learnt from: Moumouls
Repo: parse-community/parse-server PR: 9883
File: spec/CloudCodeLogger.spec.js:410-412
Timestamp: 2025-10-16T19:27:05.311Z
Learning: In spec/CloudCodeLogger.spec.js, the test "should log cloud function triggers using the silent log level" (around lines 383-420) is known to be flaky and requires the extra `await new Promise(resolve => setTimeout(resolve, 100))` timeout after awaiting `afterSavePromise` for reliability, even though it may appear redundant.

Applied to files:

  • spec/ParseGraphQLServer.spec.js
📚 Learning: 2025-08-27T09:08:34.252Z
Learnt from: EmpiDev
Repo: parse-community/parse-server PR: 9770
File: src/triggers.js:446-454
Timestamp: 2025-08-27T09:08:34.252Z
Learning: When analyzing function signature changes in Parse Server codebase, verify that call sites are actually incorrect before flagging them. Passing tests are a strong indicator that function calls are already properly aligned with new signatures.

Applied to files:

  • spec/ParseGraphQLServer.spec.js
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Benchmarks

@codecov
Copy link

codecov bot commented Nov 10, 2025

Codecov Report

❌ Patch coverage is 76.92308% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 93.07%. Comparing base (dafea21) to head (70e577e).
⚠️ Report is 3 commits behind head on alpha.

Files with missing lines Patch % Lines
src/GraphQL/ParseGraphQLServer.js 76.92% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##            alpha    #9929      +/-   ##
==========================================
- Coverage   93.07%   93.07%   -0.01%     
==========================================
  Files         187      187              
  Lines       15234    15243       +9     
  Branches      177      177              
==========================================
+ Hits        14179    14187       +8     
- Misses       1043     1044       +1     
  Partials       12       12              

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

@mtrezza
Copy link
Member

mtrezza commented Nov 17, 2025

@coderabbitai for every PR suggest an angular PR title to make a meaning change log entry for developers. Update the PR title suggestion on every commit.

@coderabbitai
Copy link

coderabbitai bot commented Nov 17, 2025

Tip

For best results, initiate chat on the files or code changes.

@mtrezza, I'll suggest Angular-style PR titles for every PR to create meaningful changelog entries, and update my suggestions with each commit.

For this PR, I suggest the following title:

Current title:

perf: Apollo parallel server init under load

Suggested title:

perf: prevent concurrent Apollo Server initialization under load

Rationale:

  • More clearly describes the action taken (prevent concurrent initialization)
  • Better communicates the value to developers reading the changelog
  • Maintains the perf: type prefix for performance improvements
  • Includes "concurrent" which better captures the race condition being fixed

Alternative option if you prefer more technical detail:

perf: use mutex to prevent parallel Apollo Server initialization

I'll monitor this PR for new commits and update my title suggestion accordingly.


✏️ Learnings added
Learnt from: mtrezza
URL: https://github.com/parse-community/parse-server/pull/9929

Timestamp: 2025-11-17T15:02:24.793Z
Learning: For Parse Server PRs, always suggest an Angular-style PR title that would make a meaningful changelog entry for developers. Update the PR title suggestion with every new commit to the PR.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 0
File: :0-0
Timestamp: 2025-11-08T13:46:04.940Z
Learning: When reviewing Parse Server PRs that add new features, always check whether the feature is documented in the README.md file, though for new Parse Server options this is optional rather than required.

@coderabbitai
Copy link

coderabbitai bot commented Nov 17, 2025

Tip

For best results, initiate chat on the files or code changes.

@mtrezza, I'll suggest Angular commit convention titles for PRs to help create meaningful changelog entries. For this PR, I recommend:

perf(graphql): prevent concurrent Apollo server initialization under load

Why this title works better for developers:

  • Scope added (graphql): Helps organize changelog entries by feature area
  • Action-oriented: "prevent concurrent" is clearer than "parallel" for describing what the fix accomplishes
  • Clear benefit: Developers immediately understand this fixes a concurrency issue during high-load startup

Alternative options:

  • perf(graphql): use mutex to prevent parallel Apollo server initialization
  • perf(apollo): avoid multiple server initializations under concurrent load

The suggested title makes it clear this is a performance improvement in the GraphQL subsystem that addresses a specific concurrency problem, making it easier for developers to understand the impact when reviewing changelogs.

I'll monitor this PR and update the title suggestion as commits are added.


✏️ Learnings added
Learnt from: mtrezza
URL: https://github.com/parse-community/parse-server/pull/9929

Timestamp: 2025-11-17T15:02:48.761Z
Learning: For Parse Server PRs, always suggest an Angular commit convention PR title that would make a meaningful changelog entry for developers. Update the PR title suggestion on every commit. The format should be: type(scope): description. Common types include feat, fix, perf, refactor, docs, test, chore. The scope should identify the subsystem (e.g., graphql, rest, push, security). The description should be action-oriented and clearly convey the change's impact to developers.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 0
File: :0-0
Timestamp: 2025-11-08T13:46:04.940Z
Learning: When reviewing Parse Server PRs that add new features, always check whether the feature is documented in the README.md file, though for new Parse Server options this is optional rather than required.

@mtrezza mtrezza changed the title perf: Apollo parallel server init under load perf: Prevent concurrent Apollo server initialization under load Nov 17, 2025
@mtrezza
Copy link
Member

mtrezza commented Nov 17, 2025

@coderabbitai is that a performance improvement or actually a bug fix?

@coderabbitai
Copy link

coderabbitai bot commented Nov 17, 2025

Tip

For best results, initiate chat on the files or code changes.

@mtrezza, excellent question! After analyzing the changes, this is actually a bug fix rather than a pure performance improvement. Here's why:

This is a race condition bug:

  • Under concurrent load, multiple _getServer() calls can trigger parallel Apollo Server initializations
  • This creates multiple server instances when only one should exist
  • Multiple instances can lead to:
    • Inconsistent state across requests hitting different instances
    • Resource leaks or exhaustion
    • Undefined behavior in the GraphQL subsystem
    • Wasted resources during initialization

Why not just a performance optimization:

  • A performance improvement optimizes working-but-slow code
  • This fixes incorrect behavior (multiple instances) that happens to also improve performance
  • The performance gain is a beneficial side effect of fixing the race condition, not the primary purpose

Suggested title update:

fix(graphql): prevent concurrent Apollo server initialization race condition

Alternative options:

fix(graphql): resolve race condition in Apollo server initialization
fix(graphql): prevent multiple Apollo server instances under concurrent load

The fix: type is more appropriate for changelog entries, as developers will understand this addresses a concurrency bug that could cause issues under load, with performance improvements as a bonus.


🧠 Learnings used
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 0
File: :0-0
Timestamp: 2025-11-17T15:02:48.761Z
Learning: For Parse Server PRs, always suggest an Angular commit convention PR title that would make a meaningful changelog entry for developers. Update the PR title suggestion on every commit. The format should be: type(scope): description. Common types include feat, fix, perf, refactor, docs, test, chore. The scope should identify the subsystem (e.g., graphql, rest, push, security). The description should be action-oriented and clearly convey the change's impact to developers.

Learnt from: mtrezza
Repo: parse-community/parse-server PR: 0
File: :0-0
Timestamp: 2025-11-17T15:02:24.793Z
Learning: For Parse Server PRs, always suggest an Angular-style PR title that would make a meaningful changelog entry for developers. Update the PR title suggestion with every new commit to the PR.

Learnt from: mtrezza
Repo: parse-community/parse-server PR: 0
File: :0-0
Timestamp: 2025-11-08T13:46:04.940Z
Learning: When reviewing Parse Server PRs that add new features, always check whether the feature is documented in the README.md file, though for new Parse Server options this is optional rather than required.

@coderabbitai
Copy link

coderabbitai bot commented Nov 17, 2025

Tip

For best results, initiate chat on the files or code changes.

@mtrezza, excellent question! After analyzing the code changes and problem statement, this is primarily a bug fix, not a performance improvement.

Why it's a bug fix:

  • The current code has a race condition: under concurrent load, multiple calls to _getServer() can trigger parallel Apollo Server initializations
  • This means multiple server instances can be created when only one should exist
  • Race conditions are functional bugs—the code doesn't behave correctly under concurrent access
  • The test validates this by ensuring 100 parallel calls return the same server instance, proving the fix addresses correctness, not just efficiency

Why the performance gain is secondary:

  • Yes, preventing duplicate initialization improves performance
  • But the root problem is incorrect behavior (multiple servers) under load, not just inefficiency
  • The performance benefit is a positive side effect of fixing the race condition

Updated PR title suggestion:

fix(graphql): prevent race condition in Apollo Server initialization

Alternative options:

  • fix(graphql): resolve concurrent Apollo Server initialization race condition
  • fix(graphql): prevent multiple Apollo Server instances under concurrent load

The fix: type is more accurate because this addresses a concurrency bug that could lead to unpredictable behavior, not just a performance optimization.


🧠 Learnings used
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 0
File: :0-0
Timestamp: 2025-11-17T15:02:48.761Z
Learning: For Parse Server PRs, always suggest an Angular commit convention PR title that would make a meaningful changelog entry for developers. Update the PR title suggestion on every commit. The format should be: type(scope): description. Common types include feat, fix, perf, refactor, docs, test, chore. The scope should identify the subsystem (e.g., graphql, rest, push, security). The description should be action-oriented and clearly convey the change's impact to developers.

Learnt from: mtrezza
Repo: parse-community/parse-server PR: 0
File: :0-0
Timestamp: 2025-11-17T15:02:24.793Z
Learning: For Parse Server PRs, always suggest an Angular-style PR title that would make a meaningful changelog entry for developers. Update the PR title suggestion with every new commit to the PR.

Learnt from: mtrezza
Repo: parse-community/parse-server PR: 0
File: :0-0
Timestamp: 2025-11-08T13:46:04.940Z
Learning: When reviewing Parse Server PRs that add new features, always check whether the feature is documented in the README.md file, though for new Parse Server options this is optional rather than required.

@mtrezza mtrezza changed the title perf: Prevent concurrent Apollo server initialization under load fix: Resource leak due to race condition creating multiple Apollo server initializations under load Nov 17, 2025
@mtrezza mtrezza changed the title fix: Resource leak due to race condition creating multiple Apollo server initializations under load fix: Race condition causing multiple Apollo server initializations under load Nov 17, 2025
@mtrezza mtrezza changed the title fix: Race condition causing multiple Apollo server initializations under load fix: Race condition causes multiple Apollo server initializations under load Nov 17, 2025
@mtrezza mtrezza changed the title fix: Race condition causes multiple Apollo server initializations under load fix: Race condition can cause multiple Apollo server initializations under load Nov 17, 2025
@mtrezza mtrezza merged commit 7d5e9fc into parse-community:alpha Nov 17, 2025
26 of 28 checks passed
parseplatformorg pushed a commit that referenced this pull request Nov 17, 2025
# [8.5.0-alpha.9](8.5.0-alpha.8...8.5.0-alpha.9) (2025-11-17)

### Bug Fixes

* Race condition can cause multiple Apollo server initializations under load ([#9929](#9929)) ([7d5e9fc](7d5e9fc))
@parseplatformorg
Copy link
Contributor

🎉 This change has been released in version 8.5.0-alpha.9

@parseplatformorg parseplatformorg added the state:released-alpha Released as alpha version label Nov 17, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

state:released-alpha Released as alpha version

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants