-
-
Notifications
You must be signed in to change notification settings - Fork 719
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
[core] Ensure onClose callbacks are invoked in reversed initialization order #2020
base: main
Are you sure you want to change the base?
Conversation
update KoinExtension.kt
6081a6c
to
9401779
Compare
9401779
to
7f8f830
Compare
`onClose` callback can be used to release allocated resources like DB connections. Some beans can depend on each other. An example: classic Web application consists of `Controller`, `Service`, `Database`. In this case, instantiation order is: 1. `Database` 2. `Service` - implements business logic, requires `Database` 3. `Controller` - REST controller, requires `Service` On application graceful shutdown, `onClose` invocation order must be reversed: 1. `Controller` - created last, destroyed first 2. `Service` - destroyed after `Controller` to avoid use-after-close 3. `Database` - destroyed after `Service` to avoid use-after-close This commit delivers implementation of `onClose` calls ordering. When instance factory creates its first instance, it means that all dependencies are also created. So it's enough to sort factories by 'first instance creation,' and then reverse the sequence when invoking `onClose`. Implementation: * global 'instance creation order' atomic counter is created * each instance factory has 'instance creation order' position * when factory creates its first instance * 'instance creation order' counter is incremented * the counter's value is saved into 'instance creation order' position of the factory * factories can be sorted by 'instance creation order' position, this can be used to order `onClose` calls
7f8f830
to
7cfa056
Compare
@@ -28,8 +30,12 @@ import org.koin.mp.Lockable | |||
/** | |||
* Koin Instance Holder | |||
* create/get/release an instance of given definition | |||
* | |||
* Implements [Comparable] to provide factories soring by instance creation order |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo: sorting
|
||
// it's required to have `Long.MAX_VALUE` instantiations happened to make this check fail, | ||
// which is not likely to happen | ||
check(instanceCreationOrderPosition < Long.MAX_VALUE) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
instanceCreationOrderPosition
default value is MAX_VALUE
and this check throw an exception if it hit MAX_VALUE
.
I'm not sure if I understand your code comment above and it seems error prone.
abstract class InstanceFactory<T>(val beanDefinition: BeanDefinition<T>) : Lockable() { | ||
abstract class InstanceFactory<T>(val beanDefinition: BeanDefinition<T>) : Lockable(), Comparable<InstanceFactory<*>> { | ||
private val instanceCreationOrderSet = AtomicBoolean(false) | ||
private var instanceCreationOrderPosition = Long.MAX_VALUE |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current design ties a child instance natural comparison to its insertion ordering within a parent collection. A Comparable
is documented as a way to define a class's natural order, not their insertion order. See Comparable and Natural Sort Order.
Instead, what if the InstanceRegistry
would handle the instances collection and closing ordering?
Here's a possible approach:
- The
InstanceRegistry
could use aConcurrentLinkedDeque
to store keys, ensuring thread-safe ordering of factory registrations. - The
InstanceRegistry
would then access the deque to order the factory instances and close them in the correct order.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same thought here. Consider another proposal @shchuko
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's see for another solution 👍 See Marcello's comment
Fixes #1510
onClose
callback can be used to release allocated resourceslike DB connections. Discussion #1507
Some beans can depend on each other.
An example: classic Web application consists of
Controller
,Service
,Database
.In this case, instantiation order is:
1.
Database
2.
Service
- implements business logic, requiresDatabase
3.
Controller
- REST controller, requiresService
On application graceful shutdown,
onClose
invocation order must be reversed:1.
Controller
- created last, destroyed first2.
Service
- destroyed afterController
to avoid use-after-close3.
Database
- destroyed afterService
to avoid use-after-closeThis commit delivers implementation of
onClose
calls ordering.When instance factory creates its first instance, it means that all dependencies are also created. So it's enough to sort factories by 'first instance creation,' and then reverse the sequence when invoking
onClose
.Implementation:
onClose
calls