#Global singletons

1 messages · Page 1 of 1 (latest)

fading halo
#

Is there a way to create a global singleton and have it work with modules?

Use Case:
I have a secret store, and previously I was just initializing it in the root module and storing an instance in a way that I could reference it from anywhere.

// in the root module
@func() async foo(token: Secret) {
  await Secrets.init(token)
  return dag.container().with(doStuff())
}
// in another file
function doStuff() {
  return container => container.withExec(['echo', Secrets.instance.get('name')])
}

That all worked fine when I was in the runtime of a single module.

Now I'm starting to split things up a bit and I'm running into issues.

@object 
class Other {
  @field() container: Container
  constructor(container) {this.container = container)
  @func() async foo() {
    return this.container.with(doStuff())
  }
}

@object()
class Root {
  @func() async entry(token: Secret) {
    await Secrets.init(token)
    const container = dag.container().from('node:20').with(doStuff())
    return new Other(container)
  }
}

The global instance still works fine while it's executing the Root module, but when it starts executing Other it failes because Secrets.instance isn't set.

I could just change it so that I have to pass the instance into everything, but that gets tedius very fast since the majority of my with helpers and modules need access to Secrets.
I also ran into an issue when I passed the instance of Secrets to a different module as it was having trouble deserializing the object. (I used @object() on the Secrets class and marked its fields with @field() as well)

unexpected result value type string for object "MotionDaggerInfisical"

The other approach that I can think of would be to pass the token: Secret into every module and always just re-initialize it. My assumption would be that this would be the more "dagger", but I'm not quite sure.

Any suggestions?

delicate otter
#

I could just change it so that I have to pass the instance into everything, but that gets tedius very fast since the majority of my with helpers and modules need access to Secrets.
...
The other approach that I can think of would be to pass the token: Secret into every module and always just re-initialize it. My assumption would be that this would be the more "dagger", but I'm not quite sure.
Yeah passing things around very explicitly is generally the way it works at the moment, for a few reasons:

  • Global state shared across all invocations of a module makes caching very hard/impossible and also just makes it harder for users to reason about the behavior of their own code.
  • Having to pass things like secrets around explicitly gives you fine grain control over what has access to the secrets and what doesn't

To make this less tedious within the context of a single module, you can wrap all the "context state" up into one object and then pass that around. Still need to pass it around explicitly but at least it's only one thing.

If you need to pass this sort of state across modules, then yeah it currently is going to require unpacking to core types like Secret around. The reason being that modules can't accept/return types from other modules (which would unleash dependency hell type problems). Dagger does have support for "interfaces" to help address this but they have only been implemented in the Go SDK so far. TS support is planned though too.

I also ran into an issue when I passed the instance of Secrets to a different module as it was having trouble deserializing the object. (I used @object() on the Secrets class and marked its fields with @field() as well)
unexpected result value type string for object "MotionDaggerInfisical"
The error here is expected but the error message itself is a bit odd. If you can share more code maybe @oak trench can check to see if the SDK needs some extra check and handling to make the error message more clear (if I had to guess it's that the function is being passed an ID string but then doesn't know how to deser it into that object, but just thinking out loud)

oak trench
#

I’m checking tomorrow