Giter Club home page Giter Club logo

hangfire.entityframeworkcore's People

Contributors

jack775544 avatar sergezhigunov avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

hangfire.entityframeworkcore's Issues

ExpirationManager giving an exception

it seems that there are foreign keys between HangFireState table and HangFireJob table
One of them is set to cascading delete and the other is not
From SQL its relatively easy to adjust but perhaps you handle this in the migration scripts and in the entity model setup ?

SQL used to fix this

-- Drop foreign key

ALTER TABLE HangfireJob
DROP FOREIGN KEY FK_HangfireJob_HangfireState_StateId;

--
-- Create foreign key

ALTER TABLE HangfireJob
ADD CONSTRAINT FK_HangfireJob_HangfireState_StateId FOREIGN KEY (StateId)
REFERENCES HangfireState(Id) ON DELETE CASCADE;

Traces

dbug: Hangfire.EntityFrameworkCore.ExpirationManager[0]
Removing outdated records from the 'HangfireCounter' table...
dbug: Hangfire.EntityFrameworkCore.ExpirationManager[0]
Removing outdated records from the 'HangfireHash' table...
dbug: Hangfire.EntityFrameworkCore.ExpirationManager[0]
Removing outdated records from the 'HangfireList' table...
dbug: Hangfire.EntityFrameworkCore.ExpirationManager[0]
Removing outdated records from the 'HangfireSet' table...
dbug: Hangfire.EntityFrameworkCore.ExpirationManager[0]
Removing outdated records from the 'HangfireJob' table...
dbug: Hangfire.Processing.BackgroundExecution[0]
Execution loop ExpirationManager:043fc230 caught an exception and will be retried in 00:03:45
Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
---> Cannot delete or update a parent row: a foreign key constraint fails (PLHFPORTAL.HangfireJob, CONSTRAINT FK_HangfireJob_HangfireState_StateId FOREIGN KEY (StateId) REFERENCES HangfireState (Id))
--- End of inner exception stack trace ---
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.Execute(IRelationalConnection connection)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.Execute(IEnumerable1 commandBatches, IRelationalConnection connection) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(IList1 entriesToSave)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(StateManager stateManager, Boolean acceptAllChangesOnSuccess)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(Boolean acceptAllChangesOnSuccess)
at Microsoft.EntityFrameworkCore.DbContext.SaveChanges(Boolean acceptAllChangesOnSuccess)
at Hangfire.EntityFrameworkCore.ExpirationManager.<>c__61.<RemoveExpired>b__6_1(DbContext context) at Hangfire.EntityFrameworkCore.EFCoreStorage.UseContext[T](Func2 func)
at Hangfire.EntityFrameworkCore.ExpirationManager.b__6_0T
at Hangfire.EntityFrameworkCore.ExpirationManager.UseLock(Action action)
at Hangfire.EntityFrameworkCore.ExpirationManager.RemoveExpiredT
at Hangfire.EntityFrameworkCore.ExpirationManager.Execute(CancellationToken cancellationToken)
at Hangfire.Processing.BackgroundExecution.Run(Action`2 callback, Object state)
dbug: Hangfire.Processing.BackgroundExecution[0]
Execution loop ExpirationManager:043fc230 will be retried in 00:03:45...

DbContext instances shouldn't be disposed

When we supply the DbContext from the factory, the library uses the dbcontext in a using statement. This causes the it to be disposed once the task is performed.

This causes a problem when using dependency injection, because if we resolve a service from the service provider, we shouldn't dispose / control its lifetime ourselves, because we're not instantiating it ourselves. So when the DI container tries to share the instance (per lifetime rules i.e. scoped/transient/singleton), it cannot reuse the dbcontext instance again, because the library has disposed it in a previous operation.

services.AddHangfire((provider, configuration) =>
    {
        var serviceScope = provider.CreateScope(); // share this scope (and dbcontext) among all calls to `contextBuilder` factory.
        configuration.UseEFCoreStorage(() => serviceScope.ServiceProvider.GetRequiredService<BlitzDbContext>(),
            new EFCoreStorageOptions());
    }
);

This is caused by these usages:

internal void UseContext(Action<DbContext> action)
{
if (action is null)
throw new ArgumentNullException(nameof(action));
using var context = CreateContext();
action(context);
}

https://github.com/sergezhigunov/Hangfire.EntityFrameworkCore/blob/main/src/Hangfire.EntityFrameworkCore/CountersAggregator.cs#L47

and any other places I'm not aware of.

The solution is to remove all using statements around dbcontext, and let the consumer decide when to dispose it. This library should simply accept whatever the contextBuilder delegate gives and use it.

The current documented solution is to use a IDbContextFactory<T>, but it creates a dbcontext for every call to CreateDbContext, which runs the initialization routine repeatedly.

https://github.com/sergezhigunov/Hangfire.EntityFrameworkCore/blob/main/README.md#using-your-own-dbcontext

This brings up the issue that it's causing unnecessary overhead that it shouldn't, though I admit that I haven't benchmarked its effect.

Error removing expired jobs with parameters

Hi,

I detect an error when testing library. If jobs are expired, this fails because HangfireJobParameter and HangFireState has entries with JobId related.

Error:

`23503: update or delete on table "HangfireJob" violates foreign key constraint "FK_HangfireJobParameter_HangfireJob_JobId" on table "HangfireJobParameter"

DETAIL: Detail redacted as it may contain sensitive data. Specify 'Include Error Detail' in the connection string to include this information.`

A possible solution is to put this on line 73 of the ExpirationManager.cs file:

// Trying remove HangfireJobParameter from expired jobs
context.Set<HangfireJobParameter>().RemoveRange(
          context.Set<HangfireJobParameter>().Where(x => expiredEntityIds.Contains(x.JobId)));

// Trying remove HangfireState from expired jobs
                context.Set<HangfireState>().RemoveRange(
                    context.Set<HangfireState>().Where(x => expiredEntityIds.Contains(x.JobId)));

Thanks

Max value size on HangfireSet

I have been using this library together with Hangfire.Console and have come across a limitation with the value size in the HangfireSet table. The console library will store values in HangfireSet and the current schema that is defined has a max size of 100. This makes it frustrating since it means that the max size of a of a log message is 100 characters long, not very large at all!

I propose that the MaxLength on HangfireSet is either removed or at least increased to 256 to match the value that is set in the SQL Server storage.

Happy to make a PR for this you agree with the changes.

Make model classes public

Currently the model classes in the project are marked as internal which is normally fine since interaction with the underlying storage should be done with the Hangfire APIs themselves.

However with the addition of EFCore compiled models the generated code that is created from running dotnet ef dbcontext optimize will have compile errors since it is trying to reference the internal code.

For example, this comes from a sample optimised model

var id = runtimeEntityType.AddProperty(
    "Id",
    typeof(long),
    propertyInfo: typeof(HangfireJob).GetProperty("Id", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
    fieldInfo: typeof(HangfireJob).GetField("<Id>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
    valueGenerated: ValueGenerated.OnAdd,
    afterSaveBehavior: PropertySaveBehavior.Throw);

The typeof(HangfireJob) in this case is a compile error since the class is not public.

I propose changing these classes to be public so optimized models will now work. Though it is not really a recommended pattern this will also allow for the use case asked for in #22 to work as well through the dbContext.Set<HangfireJob>() API.

Happy to make this change and send a PR if you are happy with the concept.

Unexpected DbUpdateConcurrencyException on ExpirationManager execution

There are a few log records like:

{
  "EventId": 0,
  "LogLevel": "Debug",
  "Category": "Hangfire.Processing.BackgroundExecution",
  "Message": "Execution ExpirationManager is in the Faulted state now due to an exception, execution will be retried no more than in 00:00:01",
  "Exception": "Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException: The database operation was expected to affect 1 row(s), but actually affected 0 row(s); data may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions.    at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ThrowAggregateUpdateConcurrencyException(Int32 commandIndex, Int32 expectedRowsAffected, Int32 rowsAffected)    at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ConsumeResultSetWithoutPropagation(Int32 commandIndex, RelationalDataReader reader)    at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.Consume(RelationalDataReader reader)    at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.Execute(IRelationalConnection connection)    at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.Execute(IEnumerable\u00601 commandBatches, IRelationalConnection connection)    at Microsoft.EntityFrameworkCore.Storage.RelationalDatabase.SaveChanges(IList\u00601 entries)    at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(IList\u00601 entriesToSave)    at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(StateManager stateManager, Boolean acceptAllChangesOnSuccess)    at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.\u003C\u003Ec.\u003CSaveChanges\u003Eb__104_0(DbContext _, ValueTuple\u00602 t)    at Microsoft.EntityFrameworkCore.Storage.NonRetryingExecutionStrategy.Execute[TState,TResult](TState state, Func\u00603 operation, Func\u00603 verifySucceeded)    at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(Boolean acceptAllChangesOnSuccess)    at Microsoft.EntityFrameworkCore.DbContext.SaveChanges(Boolean acceptAllChangesOnSuccess)    at Microsoft.EntityFrameworkCore.DbContext.SaveChanges()    at Hangfire.EntityFrameworkCore.ExpirationManager.\u003C\u003Ec__6\u00601.\u003CRemoveExpired\u003Eb__6_1(DbContext context) in D:\\git\\Hangfire.EntityFrameworkCore\\src\\Hangfire.EntityFrameworkCore\\ExpirationManager.cs:line 53    at Hangfire.EntityFrameworkCore.EFCoreStorage.UseContext[T](Func\u00602 func) in D:\\git\\Hangfire.EntityFrameworkCore\\src\\Hangfire.EntityFrameworkCore\\EFCoreStorage.cs:line 186    at Hangfire.EntityFrameworkCore.ExpirationManager.\u003CRemoveExpired\u003Eb__6_0[T]() in D:\\git\\Hangfire.EntityFrameworkCore\\src\\Hangfire.EntityFrameworkCore\\ExpirationManager.cs:line 46    at Hangfire.EntityFrameworkCore.ExpirationManager.UseLock(Action action) in D:\\git\\Hangfire.EntityFrameworkCore\\src\\Hangfire.EntityFrameworkCore\\ExpirationManager.cs:line 67    at Hangfire.EntityFrameworkCore.ExpirationManager.RemoveExpired[T]() in D:\\git\\Hangfire.EntityFrameworkCore\\src\\Hangfire.EntityFrameworkCore\\ExpirationManager.cs:line 44    at Hangfire.EntityFrameworkCore.ExpirationManager.Execute(CancellationToken cancellationToken) in D:\\git\\Hangfire.EntityFrameworkCore\\src\\Hangfire.EntityFrameworkCore\\ExpirationManager.cs:line 30    at Hangfire.Server.ServerProcessDispatcherBuilder.ExecuteComponent(Guid executionId, Object state)    at Hangfire.Processing.BackgroundExecution.Run(Action\u00602 callback, Object state)",
  "State": {
    "Message": "Execution ExpirationManager is in the Faulted state now due to an exception, execution will be retried no more than in 00:00:01"
  }
}

EFCore missing method EntityTypeBuilder`1.HasIndex at runtime

Hi

I'm using this library as an adapter between hangfire and my mysql database. Im encountering a runtime exception when the context is building/defining the models. (I'm using EFCore 3.1 as dependency withing my console projects)
This is probably exactly related to dotnet/aspnetcore#8467.

I downloaded the project and updated the package references to EFCore 3.1. Using that project as dependency makes the runtime exception not occur anymore.
I would have done a PR, but i assume updating the EFCore dependency of Hangfire.EntityFrameworkCore from 2.0 to 3.1 could be a backwards incompatible change for all users who are currently depending on the EFCore 2.X releases. Can this be tested? Maybe integrate two test projects where one depends on EFCore 2.X and the other depends on EFCore 3.X directly.

Currently i'm fine using my local copy of this library. I just wanted to let you know of this issue.

Bert

EDIT; Clarification of example projects

Schema is not respected in migration

if I do this:

        services.AddHangfire((serviceProvider, hangfireConfig) =>
            hangfireConfig.UseEFCoreStorage(
                serviceProvider.GetRequiredService<MyDbContext>,
                new EFCoreStorageOptions
                {
                    Schema = "hangfire",
                }));

with this in my onmodelcreating

        modelBuilder.OnHangfireModelCreating();

i am not seeing the hangfire schema in my migrations that get generated:

protected override void Up(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.CreateTable(
                name: "HangfireCounter",
                columns: table => new
                {
                    Id = table.Column<long>(type: "bigint", nullable: false)
                        .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
                    Key = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false),
                    Value = table.Column<long>(type: "bigint", nullable: false),
                    ExpireAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_HangfireCounter", x => x.Id);
                });

            migrationBuilder.CreateTable(
                name: "HangfireHash",
                columns: table => new
                {
                    Key = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false),
                    Field = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false),
                    Value = table.Column<string>(type: "text", nullable: true),
                    ExpireAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_HangfireHash", x => new { x.Key, x.Field });
                });

            migrationBuilder.CreateTable(
                name: "HangfireList",
                columns: table => new
                {
                    Key = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false),
                    Position = table.Column<int>(type: "integer", nullable: false),
                    Value = table.Column<string>(type: "text", nullable: true),
                    ExpireAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_HangfireList", x => new { x.Key, x.Position });
                });

            migrationBuilder.CreateTable(
                name: "HangfireLock",
                columns: table => new
                {
                    Id = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false),
                    AcquiredAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_HangfireLock", x => x.Id);
                });

            migrationBuilder.CreateTable(
                name: "HangfireServer",
                columns: table => new
                {
                    Id = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false),
                    StartedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
                    Heartbeat = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
                    WorkerCount = table.Column<int>(type: "integer", nullable: false),
                    Queues = table.Column<string>(type: "text", nullable: false)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_HangfireServer", x => x.Id);
                });

            migrationBuilder.CreateTable(
                name: "HangfireSet",
                columns: table => new
                {
                    Key = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: false),
                    Value = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false),
                    Score = table.Column<double>(type: "double precision", nullable: false),
                    ExpireAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_HangfireSet", x => new { x.Key, x.Value });
                });

            migrationBuilder.CreateTable(
                name: "HangfireJob",
                columns: table => new
                {
                    Id = table.Column<long>(type: "bigint", nullable: false)
                        .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
                    CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
                    StateId = table.Column<long>(type: "bigint", nullable: true),
                    StateName = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
                    ExpireAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
                    InvocationData = table.Column<string>(type: "text", nullable: false)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_HangfireJob", x => x.Id);
                });

            migrationBuilder.CreateTable(
                name: "HangfireJobParameter",
                columns: table => new
                {
                    JobId = table.Column<long>(type: "bigint", nullable: false),
                    Name = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false),
                    Value = table.Column<string>(type: "text", nullable: true)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_HangfireJobParameter", x => new { x.JobId, x.Name });
                    table.ForeignKey(
                        name: "FK_HangfireJobParameter_HangfireJob_JobId",
                        column: x => x.JobId,
                        principalTable: "HangfireJob",
                        principalColumn: "Id",
                        onDelete: ReferentialAction.Cascade);
                });

            migrationBuilder.CreateTable(
                name: "HangfireQueuedJob",
                columns: table => new
                {
                    Id = table.Column<long>(type: "bigint", nullable: false)
                        .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
                    JobId = table.Column<long>(type: "bigint", nullable: false),
                    Queue = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false),
                    FetchedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_HangfireQueuedJob", x => x.Id);
                    table.ForeignKey(
                        name: "FK_HangfireQueuedJob_HangfireJob_JobId",
                        column: x => x.JobId,
                        principalTable: "HangfireJob",
                        principalColumn: "Id",
                        onDelete: ReferentialAction.Cascade);
                });

            migrationBuilder.CreateTable(
                name: "HangfireState",
                columns: table => new
                {
                    Id = table.Column<long>(type: "bigint", nullable: false)
                        .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
                    JobId = table.Column<long>(type: "bigint", nullable: false),
                    Name = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false),
                    Reason = table.Column<string>(type: "text", nullable: true),
                    CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
                    Data = table.Column<string>(type: "text", nullable: false)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_HangfireState", x => x.Id);
                    table.ForeignKey(
                        name: "FK_HangfireState_HangfireJob_JobId",
                        column: x => x.JobId,
                        principalTable: "HangfireJob",
                        principalColumn: "Id",
                        onDelete: ReferentialAction.Cascade);
                });

            migrationBuilder.CreateIndex(
                name: "IX_HangfireCounter_ExpireAt",
                table: "HangfireCounter",
                column: "ExpireAt");

            migrationBuilder.CreateIndex(
                name: "IX_HangfireCounter_Key_Value",
                table: "HangfireCounter",
                columns: new[] { "Key", "Value" });

            migrationBuilder.CreateIndex(
                name: "IX_HangfireHash_ExpireAt",
                table: "HangfireHash",
                column: "ExpireAt");

            migrationBuilder.CreateIndex(
                name: "IX_HangfireJob_ExpireAt",
                table: "HangfireJob",
                column: "ExpireAt");

            migrationBuilder.CreateIndex(
                name: "IX_HangfireJob_StateId",
                table: "HangfireJob",
                column: "StateId");

            migrationBuilder.CreateIndex(
                name: "IX_HangfireJob_StateName",
                table: "HangfireJob",
                column: "StateName");

            migrationBuilder.CreateIndex(
                name: "IX_HangfireList_ExpireAt",
                table: "HangfireList",
                column: "ExpireAt");

            migrationBuilder.CreateIndex(
                name: "IX_HangfireQueuedJob_JobId",
                table: "HangfireQueuedJob",
                column: "JobId");

            migrationBuilder.CreateIndex(
                name: "IX_HangfireQueuedJob_Queue_FetchedAt",
                table: "HangfireQueuedJob",
                columns: new[] { "Queue", "FetchedAt" });

            migrationBuilder.CreateIndex(
                name: "IX_HangfireServer_Heartbeat",
                table: "HangfireServer",
                column: "Heartbeat");

            migrationBuilder.CreateIndex(
                name: "IX_HangfireSet_ExpireAt",
                table: "HangfireSet",
                column: "ExpireAt");

            migrationBuilder.CreateIndex(
                name: "IX_HangfireSet_Key_Score",
                table: "HangfireSet",
                columns: new[] { "Key", "Score" });

            migrationBuilder.CreateIndex(
                name: "IX_HangfireState_JobId",
                table: "HangfireState",
                column: "JobId");

            migrationBuilder.AddForeignKey(
                name: "FK_HangfireJob_HangfireState_StateId",
                table: "HangfireJob",
                column: "StateId",
                principalTable: "HangfireState",
                principalColumn: "Id");
        }

Cannot use a resilience policy on a DbContext due to ExpirationManager explicitly starting a Transaction

Hi,
My code is using the PostgreSQL EnableRetryOnFailure with the DbContext that is passed to the Hangfire.io library. Unfortunately, the ExpirationManager uses BeginTransaction before the SaveChanges is causing the following exception:

System.InvalidOperationException: The configured execution strategy 'NpgsqlRetryingExecutionStrategy' does not support user-initiated transactions. Use the execution strategy returned by 'DbContext.Database.CreateExecutionStrategy()' to execute all the operations in the transaction as a retriable unit. at Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.OnFirstExecution() at Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.Execute[TState,TResult](TState state, Func3 operation, Func3 verifySucceeded) at Microsoft.EntityFrameworkCore.DbContext.SaveChanges(Boolean acceptAllChangesOnSuccess) at Hangfire.EntityFrameworkCore.ExpirationManager.<>c.<RemoveExpiredJobs>b__6_1(DbContext context) at Hangfire.EntityFrameworkCore.EFCoreStorage.UseContext[T](Func2 func)
at Hangfire.EntityFrameworkCore.ExpirationManager.b__6_0()
at Hangfire.EntityFrameworkCore.ExpirationManager.UseLock(Action action)
at Hangfire.EntityFrameworkCore.ExpirationManager.RemoveExpiredJobs()
at Hangfire.EntityFrameworkCore.ExpirationManager.Execute(CancellationToken cancellationToken)
at Hangfire.Processing.BackgroundExecution.Run(Action2 callback, Object state) in C:\projects\hangfire-525\src\Hangfire.Core\Processing\BackgroundExecution.cs:line 118

Should this be able to be a flag to enable / disable transactions, or check to see if the DbContext will support a transaction?

Active?

This looks interesting and a bit active. With the churn on dotnet 5 and be using a non-official hangfire storage, an EFCore solution would be better.

Does this work well? What issues do you have? I don't mind helping out on some outstanding work if there's any.

How to use not user provided db context?

Can you add more documentation on how this library is supposed to work? At first I expected it to expose the DbContext so that I can do the following:

Jobs = await _context.Jobs
  // Do more fluent stuff
  .ToListAsync(cancellationToken)

But I could not find any way to achieve that. I am interested in having access to the context, so that I can use IQueryable. I also tried my own DbContext, but was getting SqlException: Invalid object name 'HangfireCounter'.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.