Skip to content

Major update: Apollo Server 5 migration with breaking changes#126

Merged
icebob merged 40 commits intomasterfrom
next
Sep 25, 2025
Merged

Major update: Apollo Server 5 migration with breaking changes#126
icebob merged 40 commits intomasterfrom
next

Conversation

@icebob
Copy link
Member

@icebob icebob commented Aug 1, 2025

Summary

This PR upgrades the Moleculer Apollo Server integration from Apollo Server 2 to Apollo Server 5, bringing significant modernization and breaking changes.

Breaking Changes

  • Apollo Server 5: Complete migration from Apollo Server 2 to 5
  • Node.js Requirements: Now requires Node.js >= 20.x.x (updated from >= 10.x)
  • File Upload Removal: Removed GraphQL file upload support (Apollo Server 3+ no longer supports it)
  • Healthcheck Removal: Built-in healthcheck endpoint removed (Apollo Server 4+ no longer supports it)
  • WebSocket Subscriptions: Rewritten subscription implementation from graphql-subscriptions to graphql-ws
  • GraphQL Playground: Replaced with Apollo Sandbox (Apollo Server 3+ default)

Major Updates

  • Modern Tooling: Migrated from legacy ESLint config to flat config format
  • GitHub Actions: Updated CI workflow to use latest actions (v4) and test on Node.js 20.x, 22.x, 24.x
  • Dependencies: Updated all dependencies to latest compatible versions
  • TypeScript: Improved TypeScript definitions in index.d.ts
  • Testing: Comprehensive integration test suite rewrite
  • Examples: Updated all examples to work with Apollo Server 5
  • Async Methods: Made makeExecutableSchema and generateGraphQLSchema methods async for better async/await support

Removed Features

  • File upload examples and documentation
  • Legacy Apollo Server 2/3 configuration options
  • Health check examples (examples/health/)
  • Upload examples (examples/upload/)

Files Changed

  • Complete rewrite of core service logic in src/service.js
  • Updated src/ApolloServer.js for Apollo Server 5 compatibility
  • Modernized configuration files (eslint.config.js, prettier.config.js)
  • Enhanced examples with Apollo Server 5 patterns
  • Comprehensive test suite updates
  • Updated TypeScript definitions for async method signatures

This is a major version bump (0.4.0) due to the breaking changes introduced by the Apollo Server 5 migration.

- Made makeExecutableSchema method async in service.js
- Made generateGraphQLSchema method async since it calls makeExecutableSchema
- Added await to all calling places to maintain proper async flow
- Updated TypeScript definitions to reflect Promise return types
- Updated CHANGELOG.md to document the changes

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
@icebob icebob linked an issue Aug 1, 2025 that may be closed by this pull request
@kthompson23
Copy link
Contributor

@icebob This is awesome!

A little while ago I discovered a race condition in prepareGraphQLSchema(). Since the call to this.apolloServer.stop() is async, a second request can enter prepareGraphQLSchema(). During peak times we noticed 502 errors.

We're running a local patch where we wrapped prepareGraphQLSchema() with an async mutex, which resolved the issue. I don't know if you can think of another way to solve that problem but I could open a PR against the master branch or I could send you our patch.

@icebob
Copy link
Member Author

icebob commented Aug 3, 2025

@kthompson23 please share your solution

@kthompson23
Copy link
Contributor

@kthompson23 please share your solution

@icebob Here's my branch.
master...kthompson23:moleculer-apollo-server:mutex-lock-schema-rebuild

I added the async-mutex package and wrapped the schema rebuild in the prepareGraphQLSchema method with a mutex.

@icebob
Copy link
Member Author

icebob commented Aug 12, 2025

I added the async-mutex package and wrapped the schema rebuild in the prepareGraphQLSchema method with a mutex.

@kthompson23 Are there any reason of using async-mutex library instead of a simple "preparing: boolean` property what I set to true at the fbeginning of the methods and return if true to avoid parallel executions?
Because I've checked the package and it's a 100KB package for solving a simple problem

@kthompson23
Copy link
Contributor

kthompson23 commented Aug 18, 2025

I added the async-mutex package and wrapped the schema rebuild in the prepareGraphQLSchema method with a mutex.

@kthompson23 Are there any reason of using async-mutex library instead of a simple "preparing: boolean` property what I set to true at the fbeginning of the methods and return if true to avoid parallel executions? Because I've checked the package and it's a 100KB package for solving a simple problem

@icebob The issue is that prepareGraphQLSchema is async and stops the apollo server. When the apollo server is stopped, we can't handle any other requests until the schema is rebuilt and the apollo server is started. A boolean could stop other requests from attempting to rebuild the schema/shut down the apollo server but it can't pause execution until the schema is rebuilt and the apollo server started. This race condition results in 504 errors.

@icebob
Copy link
Member Author

icebob commented Sep 10, 2025

@kthompson23 do you have any idea how I can reproduce this situation in integration tests?

@kthompson23
Copy link
Contributor

@kthompson23 do you have any idea how I can reproduce this situation in integration tests?

I'm not entirely sure. When I first "audited" this code, I decided to add the mutex because I thought we were doing redundant work. Two requests can enter prepareGraphQLSchema, which results in the schema being rebuilt twice and the graphql.schema.updated broker broadcast firing twice. I was pleasantly surprised when this resolved the 504 errors we were experiencing.

What if you first called invalidateGraphQLSchema(), then make two or more graphql requests in parallel?

- Updated eslint to version 9.36.0
- Updated jest and jest-cli to version 30.1.3
- Updated npm-check-updates to version 18.3.0
- Updated tsx to version 4.20.5
- Added a promise-based mechanism to prevent multiple preparations of the GraphQL schema in service.js
- Implemented a test case to verify that the GraphQL schema is not prepared multiple times concurrently
@icebob icebob merged commit 960cda3 into master Sep 25, 2025
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Upgrade npm lodash and node-fetch Upgrading to Apollo Server 3.x Promise based makeExecutableSchema service method

2 participants