Skip to content

Add shared FakeValuesService for multi-threaded Faker instances#1819

Open
mferretti wants to merge 2 commits into
datafaker-net:mainfrom
mferretti:feature/1814
Open

Add shared FakeValuesService for multi-threaded Faker instances#1819
mferretti wants to merge 2 commits into
datafaker-net:mainfrom
mferretti:feature/1814

Conversation

@mferretti
Copy link
Copy Markdown

Summary

  • Adds FakeValuesService.getShared(Locale) — a lazily-initialised, per-locale singleton backed by a ConcurrentHashMap, safe to share across threads because all mutable instance state uses idempotent copy-on-write caches.
  • Adds Faker.withSharedService(FakeValuesService, Locale, Random) — a factory that lets multiple threads share one FakeValuesService while each supplying its own Random, avoiding redundant YAML loading.
  • Covers the new API with three tests: singleton identity under concurrency (8 threads, CyclicBarrier), no errors under heavy concurrent load (16 threads × 10 000 iterations), and output parity with a normally constructed Faker.

Test plan

  • SharedFakeValuesServiceTest#getSharedReturnsSameInstanceUnderConcurrency — all 8 concurrent callers get the same instance
  • SharedFakeValuesServiceTest#concurrentFakersWithSharedServiceProduceNoErrors — 16 threads × 10 000 iterations with no exceptions
  • SharedFakeValuesServiceTest#withSharedServiceOutputMatchesNormalFaker — deterministic output matches a seed-equivalent normal Faker

🤖 Generated with Claude Code

Closes datafaker-net#1814

This allows multiple `Faker` instances to share a single, pre-initialized `FakeValuesService` per locale. Each `Faker` can then supply its own `Random` instance, avoiding redundant YAML loading and improving performance in concurrent scenarios.
@what-the-diff
Copy link
Copy Markdown

what-the-diff Bot commented May 18, 2026

PR Summary

  • Introduction of a new feature in Faker.java: A new method has been added which allows the configuration of shared instances. This optimizes the system when operated in multi-user scenarios, enhancing performance and efficiency.

  • Updates to FakeValuesService.java: A shared information storage, akin to a vault, has been included to hold instances of value-creating services, in a safe and secure manner across multiple users.

  • Added a retrieval feature in FakeValuesService.java: A new method is introduced to get the shared instance of service, if it exists, or create a new one. This ensures smooth flow and operation, reducing delays due to repetitive creation of services.

  • Inclusion of a new testing method: Ensuring the stability and correctness of the shared instance when being accessed by multiple users. This includes:

    • Verifying the same service instance is given to different users.
    • Asserting smooth operation when multiple users are using the service.
    • Checking that the results of shared service instances are consistent with individual instances.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds an opt-in way to share a single FakeValuesService across threads to avoid repeated YAML loading, plus a Faker factory that pairs the shared service with a per-thread Random. New concurrency tests exercise the singleton identity, behavior under load, and parity with a normally constructed Faker.

Changes:

  • New FakeValuesService.getShared(Locale) lazily caches per-locale instances in a ConcurrentHashMap.
  • New Faker.withSharedService(FakeValuesService, Locale, Random) factory wires a shared service with a per-thread RandomService.
  • New SharedFakeValuesServiceTest covering singleton identity, concurrent usage, and output parity.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
src/main/java/net/datafaker/service/FakeValuesService.java Adds SHARED_INSTANCES map and getShared(Locale) factory.
src/main/java/net/datafaker/Faker.java Adds withSharedService static factory for thread-local Fakers reusing a shared service.
src/test/java/net/datafaker/SharedFakeValuesServiceTest.java New tests for concurrent identity, no-errors under load, and output parity.

Comment on lines +87 to +96
private static final ConcurrentHashMap<Locale, FakeValuesService> SHARED_INSTANCES = new ConcurrentHashMap<>();

private final Map<RegExpContext, ValueResolver> REGEXP2SUPPLIER_MAP = new CopyOnWriteMap<>(HashMap::new);

/**
* Returns a lazily-initialized per-locale singleton. Safe to share across threads:
* all mutable instance state uses idempotent copy-on-write caches.
*/
public static FakeValuesService getShared(Locale locale) {
return SHARED_INSTANCES.computeIfAbsent(locale, l -> new FakeValuesService());
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

The locale isn't passed to the constructor — it doesn't need to be. Looking at updateFakeValuesInterfaceMap (line 85–88), locale-specific YAML is loaded lazily into fakeValuesInterfaceMap after construction, triggered by the BaseFaker constructor. The Locale key in SHARED_INSTANCES does exactly what it needs to: it ensures all threads using Locale.ENGLISH share one FakeValuesService instance which then lazily accumulates the English data once. Locale.FRENCH gets a separate one. The whole point is that the n-thread scenario from the issue — same locale, different Random — gets one service loaded once.

Comment thread src/main/java/net/datafaker/service/FakeValuesService.java
addPath and addUrl are non-idempotent mutators: calling them on a shared instance would silently affect every consumer of that singleton. Address this by adding a volatile boolean `shared` flag set by getShared(), and guarding both methods with an UnsupportedOperationException fail-fast.

Also rewrites the getShared Javadoc to accurately describe the design: the locale parameter is a cache-partition key (not a constructor arg), YAML is loaded lazily by BaseFaker after construction, and mixing locales between getShared and withSharedService is unsupported.

Adds sharedInstanceRejectsAddPathAndAddUrl test to cover both guards.
@codecov-commenter
Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 77.77778% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 92.46%. Comparing base (2e8ef4d) to head (d3f174e).
⚠️ Report is 18 commits behind head on main.

Files with missing lines Patch % Lines
.../java/net/datafaker/service/FakeValuesService.java 75.00% 0 Missing and 2 partials ⚠️
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.
Additional details and impacted files
@@             Coverage Diff              @@
##               main    #1819      +/-   ##
============================================
+ Coverage     92.24%   92.46%   +0.21%     
- Complexity     3479     3518      +39     
============================================
  Files           341      343       +2     
  Lines          6838     6970     +132     
  Branches        670      684      +14     
============================================
+ Hits           6308     6445     +137     
+ Misses          362      359       -3     
+ Partials        168      166       -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.

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.

3 participants