Azure / Azure/azure-functions-java-worker

Implement `Closeable` in `FunctionInstanceInjector` interface and call `close` on JVM shutdown

Open
#812 4 comments 0 reactions 1 assignee Claimed by @ahmedmuhsin View on GitHub
area:java-functions
Dominant language
Java
Stars
103
Forks
74
Avg merge
4d 8h
Merged PRs (30d)
2

Description

[Azure Functions Java supports dependency injection](https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference-java?tabs=bash%2Cconsumption#use-dependency-injection-in-java-functions) by implementing `com.microsoft.azure.functions.spi.inject.FunctionInstanceInjector` and registering the implementation via SPI. However, when the DI container creates resources that need to be closed (via the `Closeable` interface), those resources will never have their `close` method called, as Azure Functions and the `FunctionInstanceInjector` interface provide no way of doing so. Similarly, there does not appear to be *any* way of closing resources on a graceful shutdown of the Azure Functions runtime/host (See #113, #729).

[Official documentation](https://learn.microsoft.com/en-us/azure/azure-functions/manage-connections?tabs=csharp#static-clients) states:

> To avoid holding more connections than necessary, reuse client instances rather than creating new ones with each function invocation. We recommend reusing client connections for any language that you might write your function in.

And:

> *Do not* create a new client with every function invocation.

Great - I would like to have my DI container hold a singleton for various clients (e.g., a Ktor `HttpClient`, or a database client that uses a HikariCP connection pool) and then have function invocations retrieve those clients from the container. Unfortunately, it does not currently seem possible to ensure these resources close properly.

## Proposed Solution
Update `FunctionInstanceInjector` to implement `Closeable`, and update the Azure Functions runtime to call the `close` method when the runtime/host shuts down. The AF runtime is currently responsible for creating an instance of `FunctionInstanceInjector`, so it feels appropriate that it should be responsible for disposing of it.

Here's an example of what I'd like to be able to do (in Kotlin, using the Koin DI library):

```kotlin
abstract class KoinFunctionInstanceInjector(
appDeclaration: KoinApplication.() -> Unit,
) : FunctionInstanceInjector {
private val application = koinApplication(appDeclaration)

override fun getInstance(clazz: Class): T = application.koin.get(clazz.kotlin)

// Currently a compilation error, because `FunctionInstanceInjector` does not implement `Closeable`
override fun close() = application.close()
}
```

Then define a concrete class like:

```kotlin
class MyFunctionInstanceInjector :
KoinFunctionInstanceInjector({
modules(
module {
single { OkHttp.create() } onClose { it?.close() } bind HttpClientEngine::class
single { HikariDataSource(/*...*/) } onClose { it?.close() } bind DataSource::class
// ...
},
)
})
```

And registering `MyFunctionInstanceInjector` via SPI. Calling `application.close` in `KoinFunctionInstanceInjector` ends up calling the `onClose` lambda for any/all instance definitions in the Koin module, allowing the `HttpClientEngine` and `HikariDataSource` instances to be closed properly.

The only thing missing is ensuring that the `MyFunctionInstanceInjector` instance that AF creates via SPI will have its `close` method called.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.