{"id":19991089,"url":"https://github.com/icsharp/Hangfire.Topshelf","last_synced_at":"2025-05-04T10:31:07.474Z","repository":{"id":82319654,"uuid":"73374718","full_name":"icsharp/Hangfire.Topshelf","owner":"icsharp","description":"Best practice for hangfire samples","archived":false,"fork":false,"pushed_at":"2017-01-03T10:19:54.000Z","size":908,"stargazers_count":207,"open_issues_count":1,"forks_count":62,"subscribers_count":13,"default_branch":"master","last_synced_at":"2024-11-13T04:53:06.197Z","etag":null,"topics":["hangfire","message-bus","message-queue","scheduled-jobs","scheduled-tasks","scheduler-service","topshelf"],"latest_commit_sha":null,"homepage":null,"language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/icsharp.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-11-10T11:13:42.000Z","updated_at":"2024-07-10T07:57:36.000Z","dependencies_parsed_at":null,"dependency_job_id":"f94659f6-a145-44fe-ba8a-557c4a86b824","html_url":"https://github.com/icsharp/Hangfire.Topshelf","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/icsharp%2FHangfire.Topshelf","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/icsharp%2FHangfire.Topshelf/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/icsharp%2FHangfire.Topshelf/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/icsharp%2FHangfire.Topshelf/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/icsharp","download_url":"https://codeload.github.com/icsharp/Hangfire.Topshelf/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252320100,"owners_count":21729065,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["hangfire","message-bus","message-queue","scheduled-jobs","scheduled-tasks","scheduler-service","topshelf"],"created_at":"2024-11-13T04:51:36.543Z","updated_at":"2025-05-04T10:31:07.466Z","avatar_url":"https://github.com/icsharp.png","language":"C#","funding_links":[],"categories":["C\\#"],"sub_categories":[],"readme":"# Hangfire.Topshelf\n\n[![Build status](https://ci.appveyor.com/api/projects/status/5s9ujdp48l3w0o8i?svg=true)](https://ci.appveyor.com/project/icsharp/hangfire-topshelf)\n\nTo initialize this repo, you need to run git command `git submodule update --init --recursive` after you clone the master repo.\n\nSamples as below:\n\n## Host [Hangfire](https://github.com/HangfireIO/Hangfire) server in windows service using [Topshelf](https://github.com/Topshelf/Topshelf)\n\n- Impl interface `ServiceControl` based on `OWIN`.\n\n```csharp\n/// \u003csummary\u003e\n/// OWIN host\n/// \u003c/summary\u003e\npublic class Bootstrap : ServiceControl\n{\n    private readonly LogWriter _logger = HostLogger.Get(typeof(Bootstrap));\n    private IDisposable webApp;\n    public string Address { get; set; }\n    public bool Start(HostControl hostControl)\n    {\n        try\n        {\n            webApp = WebApp.Start\u003cStartup\u003e(Address);\n            return true;\n        }\n        catch (Exception ex)\n        {\n            _logger.Error($\"Topshelf starting occured errors:{ex.ToString()}\");\n            return false;\n        }\n\n    }\n\n    public bool Stop(HostControl hostControl)\n    {\n        try\n        {\n            webApp?.Dispose();\n            return true;\n        }\n        catch (Exception ex)\n        {\n            _logger.Error($\"Topshelf stopping occured errors:{ex.ToString()}\");\n            return false;\n        }\n\n    }\n}\n```\n\n- Extension method `UseOwin`\n\n``` csharp\npublic static HostConfigurator UseOwin(this HostConfigurator configurator, string baseAddress)\n{\n    if (string.IsNullOrEmpty(baseAddress)) throw new ArgumentNullException(nameof(baseAddress));\n\n    configurator.Service(() =\u003e new Bootstrap { Address = baseAddress });\n\n    return configurator;\n}\n```\n\n- Start windows service\n\n```csharp\nstatic int Main(string[] args)\n{\n    log4net.Config.XmlConfigurator.Configure();\n\n    return (int)HostFactory.Run(x =\u003e\n    {\n        x.RunAsLocalSystem();\n\n        x.SetServiceName(HangfireSettings.ServiceName);\n        x.SetDisplayName(HangfireSettings.ServiceDisplayName);\n        x.SetDescription(HangfireSettings.ServiceDescription);\n\n        x.UseOwin(baseAddress: HangfireSettings.ServiceAddress);\n\n        x.SetStartTimeout(TimeSpan.FromMinutes(5));\n        //https://github.com/Topshelf/Topshelf/issues/165\n        x.SetStopTimeout(TimeSpan.FromMinutes(35));\n\n        x.EnableServiceRecovery(r =\u003e { r.RestartService(1); });\n    });\n}\n\n```\n\n## Using IoC with [Autofac](https://github.com/autofac/Autofac)\n\n- Register components using `Autofac.Module`\n\n```csharp\n/// \u003csummary\u003e\n/// Hangfire Module\n/// \u003c/summary\u003e\npublic class HangfireModule : Autofac.Module\n{\n    protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry, IComponentRegistration registration)\n    {\n        base.AttachToComponentRegistration(componentRegistry, registration);\n\n        // Handle constructor parameters.\n        registration.Preparing += OnComponentPreparing;\n\n        // Handle properties.\n        registration.Activated += (sender, e) =\u003e InjectLoggerProperties(e.Instance);\n    }\n\n    private void InjectLoggerProperties(object instance)\n    {\n        var instanceType = instance.GetType();\n\n        // Get all the injectable properties to set.\n        // If you wanted to ensure the properties were only UNSET properties,\n        // here's where you'd do it.\n        var properties = instanceType\n            .GetProperties(BindingFlags.Public | BindingFlags.Instance)\n            .Where(p =\u003e p.PropertyType == typeof(ILog) \u0026\u0026 p.CanWrite \u0026\u0026 p.GetIndexParameters().Length == 0);\n\n        // Set the properties located.\n        foreach (var propToSet in properties)\n        {\n            propToSet.SetValue(instance, LogProvider.GetLogger(instanceType), null);\n        }\n    }\n\n    private void OnComponentPreparing(object sender, PreparingEventArgs e)\n    {\n        e.Parameters = e.Parameters.Union(new[]\n                {\n                new ResolvedParameter(\n                    (p, i) =\u003e p.ParameterType == typeof(ILog),\n                    (p, i) =\u003e LogProvider.GetLogger(p.Member.DeclaringType)\n                ),\n                });\n    }\n\n    /// \u003csummary\u003e\n    /// Auto register\n    /// \u003c/summary\u003e\n    /// \u003cparam name=\"builder\"\u003e\u003c/param\u003e\n    protected override void Load(ContainerBuilder builder)\n    {\n        //register all implemented interfaces\n        builder.RegisterAssemblyTypes(ThisAssembly)\n            .Where(t =\u003e typeof(IDependency).IsAssignableFrom(t) \u0026\u0026 t != typeof(IDependency) \u0026\u0026 !t.IsInterface)\n            .AsImplementedInterfaces();\n\n        //register speicified types here\n        builder.Register(x =\u003e new RecurringJobService());\n    }\n}\n```\n\n- Extension method `UseAutofac`\n\n```csharp\npublic static IContainer UseAutofac(this IAppBuilder app, HttpConfiguration config)\n{\n    if (config == null) throw new ArgumentNullException(nameof(config));\n\n    var builder = new ContainerBuilder();\n\n    var assembly = typeof(Startup).Assembly;\n\n    builder.RegisterAssemblyModules(assembly);\n\n    builder.RegisterApiControllers(assembly);\n\n    var container = builder.Build();\n\n    config.DependencyResolver = new AutofacWebApiDependencyResolver(container);\n\n    GlobalConfiguration.Configuration.UseAutofacActivator(container);\n\n    return container;\n}\n```\n\n## Register `RecurringJob` automatically\n\n- Usage\n\n```csharp\npublic class RecurringJobService\n{\n    [RecurringJob(\"*/1 * * * *\")]\n    [DisplayName(\"InstanceTestJob\")]\n    [Queue(\"jobs\")]\n    public void InstanceTestJob(PerformContext context)\n    {\n        context.WriteLine($\"{DateTime.Now.ToString(\"yyyy/MM/dd HH:mm:ss\")} InstanceTestJob Running ...\");\n    }\n\n    [RecurringJob(\"*/5 * * * *\")]\n    [DisplayName(\"JobStaticTest\")]\n    [Queue(\"jobs\")]\n    public static void StaticTestJob(PerformContext context)\n    {\n        context.WriteLine($\"{DateTime.Now.ToString(\"yyyy/MM/dd HH:mm:ss\")} StaticTestJob Running ...\");\n    }\n}\n\npublic interface ISampleService : IAppService\n{\n    /// \u003csummary\u003e\n    /// simple job test\n    /// \u003c/summary\u003e\n    /// \u003cparam name=\"context\"\u003e\u003c/param\u003e\n    [RecurringJob(\"0 4 1 * *\")]\n    [AutomaticRetry(Attempts = 3)]\n    [DisplayName(\"SimpleJobTest\")]\n    [Queue(\"jobs\")]\n    void SimpleJob(PerformContext context);\n}\n\n```\n\nIn app start, using extension method `UseRecurringJob` to assign the types targeted by `RecurringJobAttribute`:\n\n`GlobalConfiguration.Configuration.UseRecurringJob(typeof(RecurringJobService), typeof(ISampleService))`\n\n## Architecture\n\n### Monolithic\n\n![Monolithic](monolithic.png)\n\n### Cluster\n\n![Cluster](cluster.png)\n\n\n\n\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ficsharp%2FHangfire.Topshelf","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ficsharp%2FHangfire.Topshelf","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ficsharp%2FHangfire.Topshelf/lists"}