hey is there a direct path to hooking getInstance?
# box-products
d
hey is there a direct path to hooking getInstance?
from:
Copy code
application.wirebox.getInstance() = {
  result = <ortus stuff>;
  return result;
}
to
Copy code
application.wirebox.getInstance() = {
  if (<http://arguments.xyz|arguments.xyz> == "something") {
    result = <our stuff>
    otherResult = <call actual getInstance>
    return <do stuff with both>;
  }
  else {
    return <call actual getInstance>
  }
}
s
what is the use case?
d
Looking to experiment with passing off getInstance calls that are AOT (ahead of time) constructible (in the sense that they take zero arguments to construct, and constructing them has no dependencies on time of day or whatever) to an instance pool that has already constructed them. so something like
Copy code
getInstance() = {
  if (isAotConstructible(binding)) { return pool.getOrCreate(binding); }
  else { return defaultGetInstance(...); }
}
s
I think this is how the Wirebox binder already works with singletons?
d
yes, probably; but not all things that are possibly AOT constructible are singletons.
b
@David Rogers I still don't understand what you're trying to do. It seems you're reinventing stuff WireBox already does for you. If you want something that's created no more than once, and created on demand the first time you ask for it, then simply mark then as singletons.
If you want the singleton eagerly-created on app startup without waiting, mark it as eager init.
And if you want something that's created as many times as necessary and still created on demand, then just use it as a normal transient
WireBox also has a concept of scopes. The two scopes everyone knows are • singleton • noscope (transient) But there is also • request • session • cachebox • custom (you build it)
they take zero arguments to construct, and constructing them has no dependencies on time of day or whatever
☝️ This also describes basically every CFC ever which has no constructor args defined. There's nothing specical about that, it's just a CFC like any other.
WireBox also has a concept of DSL namespaces, which you can register your own to completely encapsulate building even non-CFC instances.
coldbox:xx
and
logbox:xxx
are examples of this. You can register a
foobar:
scope which defers to your own custom builder so whether someone asks for
foobar:brad
or
foobar:sam
your custom factory can decide what gets built.
And finally, WireBox has interception announcements which you can tap into and get even further control over what gets built https://wirebox.ortusbooks.com/usage/wirebox-event-model/wirebox-events
Re-reading your post again, if you're wanting to have a pool of pre-built objects to choose from to return, I think a custom scope may be the best approach, but I don't understand how you will "return" the items to the pool when you're done with them, assuming this is for object re-use in the pool.
d
maybe a pool is the wrong term. I want
LinkedBlockingDeque<Future<cfc>>
, and I can pull from it, and repopulate it from time to time.
b
Is the idea that you're not returning the items, just pre-creating a bunch so you can get them right away without waiting?
d
that's the general goal, yes
all the autowiring will have been done
b
Create a custom scope that simply uses an array and any time the array gets low, fire off a thread to create a few hundred more and prepend them into the array
That's an interesting feature though to consider for the core of WireBox. Will you have a different pool for each type of instance. i.e. a pool of pre-created User objects, another pool of Address objects, etc
d
so, I have something like that working. But, I'd like existing code, that does:
Copy code
getInstance("foo")
I want foo to "silently" pull from the queue
b
Also note, ColdBox 7 adds a feature that caches a bunch of the injections to speed up instance creation
I want foo to "silently" pull from the queue
Yes, exactly. And I'm telling you to use a custom scope to do so, lol
Copy code
component scope="pooled" {}
Where you write the code in the pooled scope to pre-create items and store them in an array for use
d
i think I did the same thing, with
map("foo").into("pooled")
or thereabouts. Wasn't sure if I could control 3rd party dependencies that way? Like I know some module is binded as "X" by default, I'd also like "X" to participate in this
b
Scopes are called as such because they can control how long an object lives, by deciding when to return the same object on subsequent calls. But as they wrap the actual building of the instance, they also have the ability to control how the object is built as well.
Not entirely sure what you mean by "3rd party" dependencies
d
something I box installed
b
Are these like CFC's you don't control which are simply part of some installed module?
You can map anything as another mapping.
Mappings are just like the recipe for how to build something
So you can create a mapping that builds another mapping
d
I think I need to learn more about injectors/binders/scopes heh
b
Copy code
map("Luis").toDSL("someAlreadyExistingModel@RandomModule").into( "pooled" )
d
if I do that, then callers hardcoded to inject "someAlreadyExistingModel@RandomModule" won't get the pooled version, is that right?
1
b
And then you call
Copy code
getInstance( 'luis' )
or
Copy code
property name="thing" inject="luis";
and as part of bulding that mapping, it delegates to the other mapping
d
ah, but I'd like them to get the pooled version, using the (uh..) "unpooled name". I want them to be tricked into getting the pooled version.
b
Right, I mean at some point you have to assume the other developers who wrote their code injected what they wanted. You're asking how to eat at Applebees, but intercept the waiter so when anyone orders a beer they get apple juice instead 🙂 '
d
that's right.
b
You can probably modify the mappings in the binder on the fly, but you'd have to wait until everything was registered, and not all mappings are registered up front
For instance
Copy code
getinstance( 'com.path.to.component' )
creates a mapping, but not until the instant it's asked for the first time
I would look back at the interceptors
beforeInstanceCreation
may be of use if you can modify the mapping on the fly before it's built
s
ApplebeesInterceptor.cfc
👍 1
b
So basically, inspect the mapping and if it meets your criteria, fiddle with what the mapping actually calls for (scope, etc) prior to the actual building of it
d
i'mma keep reading! thanks Brad
b
If that happens too late, (it may happen after the scope has been invoked), then look into
afterInstanceInspection
which says this
Called after an object mapping has been completely processed with its DI metadata discovery. This is your last chance to change or modify the DI data in the mapping before it is cached.
This is a super interesting usecase though. I'll mull over what it could look like to have a first-class feature of WireBox that did this. Do you have any links for precedent on this sort of feature and how other ioc containers do it?
It seems like it would really be most useful if you had a server with spikes of traffic and then lulls in between where the server could pre-create some instances in its down time to be ready for the next request. If you were under constant load, I doubt it would do much good since you'd just be creating stuff as you used it regardless.
But basically, you'd be trading off some free RAM for pre-built stuff
d
Yes, it would trade space for time. To be generally applicable would require a PID controller like mechanism that ramps up / down AOT instance pool queue sizes based on perceived need. But I'm just kicking the tires to see if it's possible or that (given no space limitations) it does save considerable time.
b
Also, based on my understanding now, this wouldn't really be for singletons, right? Since there's only one, there's no need to pool anything.
It seems like this would basically have to be for transients
d
That's correct, yes. Any time where doing getInstance("Foo") really does build a new Foo, but you'd like to amortize the time it takes to do so.
👍 1
b
Even if you just kept a pool of 100 or 1000 objects and didn't ramp up/down that would still be an interesting proof of concept
Nice, I like it. And sorry it took a few messages to finally warp my brain around what you were asking.
Instead of Applebee's this is like the little window in the McDonalds kitchen where the cooks just make a bunch of extra cheeseburgers and fries during peak times so when an order comes in, there's just a burger and fries sitting there ready to go.
🎯 1