-
Notifications
You must be signed in to change notification settings - Fork 16
Description
A user has reported that invoking UrlEndpoint(...) on a shared ServerImagekit (or Imagekit) instance from multiple threads can result in a System.InvalidOperationException. The error indicates that a non-concurrent internal collection or state is being mutated by multiple threads simultaneously.
System.InvalidOperationException: Operations that change non-concurrent collections must have exclusive access.
A concurrent update was performed on this collection and corrupted its state.
The collection's state is no longer correct.
It appears the library is mutating some shared, non-thread-safe state (perhaps a collection or internal field) when UrlEndpoint(...) is invoked in parallel.
Note: Although one might typically set the endpoint once at initialization, some use cases require dynamically switching endpoints in parallel. In such scenarios, the SDK can throw the above exception.
Steps to Reproduce
- Create a single
ServerImagekitinstance with an initial endpoint.
var _imagekit = new ServerImagekit(
"public_key_here",
"private_key_here",
"https://ik.imagekit.io/realedo/"
);- In parallel (e.g., using Parallel.For or multiple threads), alternate calls to .UrlEndpoint(".../tera/") and .UrlEndpoint(".../another/").
- Generate URLs (e.g. kit.Url(...).Generate()) between these calls to simulate typical usage in a concurrent environment.
Here’s a minimal code snippet that triggers the error on many machines:
using System;
using System.Threading.Tasks;
using Imagekit; // or relevant namespace
public class Program
{
public static void Main()
{
var _imagekit = new ServerImagekit("public_key", "private_key", "https://ik.imagekit.io/realedo/");
Parallel.For(0, 10000, new ParallelOptions { MaxDegreeOfParallelism = 16 }, i =>
{
try
{
// Randomly switch endpoint
if (i % 2 == 0)
{
_imagekit.UrlEndpoint("https://ik.imagekit.io/realedo/tera/");
}
else
{
_imagekit.UrlEndpoint("https://ik.imagekit.io/realedo/another/");
}
// Optional small delay to increase concurrency
Task.Delay(1).Wait();
var url = _imagekit.Url().Path($"test{i}.jpg").Generate();
Console.WriteLine($"{i}: {url}");
}
catch (Exception ex)
{
Console.WriteLine($"{i}: {ex.GetType().Name} -> {ex.Message}");
}
});
Console.WriteLine("Done.");
Console.ReadKey();
}
}Observed Behavior
In some runs (especially with higher iteration counts and parallelism), System.InvalidOperationException is thrown, complaining about concurrent access to an internal, non-concurrent collection.
Expected Behavior
- Either the SDK handles concurrent modifications safely (e.g., using thread-safe data structures or internal locking), or
- The documentation explicitly states that changing UrlEndpoint(...) in parallel is unsupported, guiding users to create separate Imagekit instances or synchronize their calls.
Suggested Solutions
- Immutability: Make methods like UrlEndpoint(...) return a new ServerImagekit object instead of mutating the existing instance.
- Thread-Safe Mutations: Use lock statements or thread-safe collections internally so multiple threads can safely modify the endpoint configuration.
- Documentation Update: If dynamic endpoint changes aren’t intended to be thread-safe, clarify that in the docs, suggesting patterns like “create separate clients” or “lock around calls.”
Additional Context
Some users have valid scenarios requiring multiple endpoints (e.g., multi-tenant setups) and may switch them at runtime. If the SDK cannot support concurrent reconfiguration, it should at least guide developers toward safe usage patterns.