4

I am using Azure Functions version 2.x. It has built-in support for dependency injection.

So I can register my service IMyService for DI at singleton scope using:

public class Startup : FunctionsStartup
{
    public override void Configure(IFunctionsHostBuilder builder)
    {
        builder.Services.AddSingleton<IOther, DefaultOther>();
        builder.Services.AddSingleton<IMyService, DefaultMyService>();  // IMyService depends on IOther.
    }
}

An instance of DefaultMyService is created the first time the function gets executed. This means the first request is slower because it does heavy initialization that happens inside DefaultMyService (it populates cache, etc.).

Question: Is there a way to have DefaultMyService created earlier than the first request?

A similar question was asked for asp.net core, and the answers there suggests a few solutions, but none of them works in the context of a function app:

Option 1: Create an instance of my service (initialization happens here), and then register the instance (instead of registering the type)

var foo = new Foo();
services.AddSingleton<IFoo>(foo);

This doesn't work because in my case IMyService depends on other services, which are not instantiated at the time when I am registering IMyService in the Configure method. It fails with an error that's described here.

Option 2: Other suggestion is to use overloaded Configure method:

public void Configure(IApplicationBuilder app, IFoo foo) 
{
    ...
}

This also doesn't work because in case of function app, the only configure method that gets executed is Configure(IFunctionsHostBuilder builder), and other overloads are not called.

Turbo
  • 2,179
  • 18
  • 38
  • After deployment, schedule a diagnostic method call. Not only will this test health but also get the function to be in a _warm_ state in preparation for the first client call –  Jun 02 '19 at 23:42
  • How/where are the other dependencies registered? – Nkosi Jun 03 '19 at 00:13
  • @Nkosi In the same method, but before IMyService. Also it depends on ILoggerFactory which is pre-registered by the function app host before Configure is called. I edited the code sample in question to make it clearer. – Turbo Jun 03 '19 at 00:37

1 Answers1

3

because it does heavy initialization that happens inside DefaultMyService

This is where the core of the problem lies. As Mark Seemann explained here, Injection constructors should do nothing more checking for null and storing incoming dependencies. Any time you do any I/O or invoke the class's dependencies inside the constructor, you'll get in trouble.

Your question seems similar to this q/a, and my advise would be the same: extract the initialization logic out of the constructor and either do the following:

  • Do the initialization before wiring the object graph and supply the DI configuration with an initialized object, or
  • Resolve and invoke an object graph directly after the registration phase, and before the first request, in such way that the data can be initialized.
Steven
  • 166,672
  • 24
  • 332
  • 435