Skip to content
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

Using multiple instances of a 'test host' that arranges Hangfire using the 'MemoryStorage' provider #39

Open
bhehe opened this issue Aug 3, 2022 · 4 comments

Comments

@bhehe
Copy link

bhehe commented Aug 3, 2022

Context

I'm using a 'test host' based approach in some of my integration tests and each test case/method creates its own discrete instance.

When registering Hangfire we're using the MemoryStorage provider and seeing some odd behaviors that we're suspecting may relate to use of this storage provider. On the main page @ https://github.com/perrich/Hangfire.MemoryStorage there is mention of the following:

  • data are stored in memory using a dictionary in a static way (See Data created at the storage creation)

What I'm observing happening is that we can run the tests 1-by-1 and they pass just fine. But when running them as a suite/set of tests they fail with 1 passing (first one ran) and the others then failing. We're using xUnit and we have measures in place to prevent concurrent/parallel execution of the tests that leverage the test host so I don't think that's the root cause here.

Previously we would see these failures and had little to no real clues to go on, but I've recently leveraged the newer method for triggering recurring jobs that does return a JobId when successful. Our helper code for triggering jobs includes a guard/check for null values being returned (indicating that it couldn't trigger the job) which throws an exception. Now with that check in place, I can see that the 1st test host instance / test case executes fine; It builds the test host/registers the job & triggers the job with the test passing. But the 2nd & subsequent test cases are failing saying they can't even trigger the referenced job. I know the job is registered by the test as they pass when ran individually so that doesn't seem like it should be the root-cause.

When I started to analyze why the job couldn't even be triggered, I started looking into where anything stateful could be complicit and the use of the MemoryStorage came to mind. With the statement on the main repo page about using static members to manage state in this provider I thought I had my 'Ah Ha!' moment - but on reviewing the current code it doesn't appear to truly be using static state management.

I reviewed the following files to try and trace the behavior & state management/lifetime:

  • GlobalConfigurationExtensions
  • MemoryStorage
  • Data

The impression I have is that we are using a unique instance of a test host for each test method/case, we use Hangfire's extension methods to register it and then we register each job using the RecurringJob.AddOrUpdate method. While registering Hangfire we call the 'UseMemoryStorage' method passing in the MemoryStorageOptions and that in turn would get a new instance of Data for each discrete use of the test host/Hangfire.

As an attempt to verify if the storage provider and static state management was complicit, I updated the tests to register all of the jobs in each test case so I'd know "yes they're registered" but that didn't resolve the issue.

Questions

1 - Is the state really 'static' as described on the main page?

If I am using multiple instances of a test host, each with their own discrete registration of Hangfire & use of MemoryStorage provider would you expect to see the overall state of registered jobs be impacted as described? I'm wondering if that comment is perhaps from an older version and just out of date (perhaps needing removed/clarified).

2 - Would Hangfire itself be holding onto the StorageConnection (which is MemoryProvider) and yield the behavior described?

Once I noted the statement on this storage provider about static state, I started off here but I'm now wondering if there's something on the Hangfire side that would 'hold onto' the state this provider is using.

@bhehe
Copy link
Author

bhehe commented Aug 3, 2022

The question as to "really is static" remains, but I realized there is another 'in memory' storage provider variant with the other one coming from the Hangfire team itself, I swapped to this alternate implementation and my problem remains.

Disregard this issue other than potentially clarifying the static angle and perhaps updating the page to reflect the actual current state.

Thanks!

@perrich
Copy link
Owner

perrich commented Aug 4, 2022

You've right, if this version does not fit to the purpose the more recent MemoryProvider could resolve it.

@bhehe
Copy link
Author

bhehe commented Aug 16, 2022

fwiw, if anyone encounters this later. the same issue exists with the Hangfire-provided version of the in-memory storage provider.

When switching to use of a SQL Server local DB for storage, the issue does not occur. So this appears to be an issue with the in-memory approach generically and how those storage providers manage their internal state for the lifetime of the test runner.

@perrich
Copy link
Owner

perrich commented Aug 20, 2022

Thank you for your check and advise.

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

No branches or pull requests

2 participants