@neko-kai No, I couldn't find that I use any of what you suggested. Does the error message suggest that it has been disabled?
This is my WiringTest
+ some context
object WiringTest
extends PlanCheck.Main(
MainProd,
cfg = PlanCheckConfig(checkConfig = false), // Could this be the cause? I can't easily enable it.
)
object MainProd extends MainBase(Activation(Repo -> Repo.Prod))
abstract class MainBase(activation: Activation) extends RoleAppMain.LauncherBIO2[IO] {
override def requiredRoles(argv: RoleAppMain.ArgV): Vector[RawRoleParams] = Vector(RawRoleParams(MyRole.id))
override def pluginConfig: PluginConfig = PluginConfig.cached(packagesEnabled = Seq("com.myproject.plugins")) // Contains all plugin defs
override protected def roleAppBootOverrides(argv: RoleAppMain.ArgV): Module =
super.roleAppBootOverrides(argv) ++ new ModuleDef {
make[Activation].named("default").fromValue(activation)
}
}
// Also have a RunLocal in test project to run application using containers
object RunLocal extends MainBase(Activation(Repo -> Repo.Prod)) {
override def pluginConfig: PluginConfig =
super.pluginConfig
.overriddenBy(ContainerPlugin)
}
I could get the ProvisioningException
when running RunLocal
but not when running WiringTest
.
Also, I could see when running RunLocal
that it prints (some while before error message)
W 2021-06-14T13:22:35.132 (PlanCircularDependencyCheck.scala:21) …arDependencyCheck.verify.18 [1:main] phase=late Circular dependency has been resolved with proxy for key={type.com.myproject.A}
import izumi.functional.bio.{F, IO2}
import zio.{Runtime, Schedule, ZIO}
import zio.duration._
object Main extends scala.App {
val rt = Runtime.default
val repeatEffect = ZIO.effect(println("Effect")).repeat(Schedule.spaced(1.second))
//rt.unsafeRun(repeatEffect)
def repeatEffectTF[F[+_, +_]: IO2] =
F.sync(println("Effect TF"))
rt.unsafeRun(repeatEffectTF[zio.IO])
}
repeatEffectTF
repeat
capabilitiestrait Scheduler2[F[_, _]] {
def repeat[E, A, B](eff: F[E, A])(scheduler: Schedule[Clock, A, B]): F[E, B]
}
object Scheduler2 {
def apply[F[+_, +_]: Scheduler2]: Scheduler2[F] = implicitly
implicit def fromZIO(implicit zClock: Clock): Scheduler2[IO] = new Scheduler2[IO] {
override def repeat[E, A, B](eff: IO[E, A])(scheduler: Schedule[Clock, A, B]): IO[E, B] = {
eff.repeat(scheduler).provide(zClock)
}
}
trait Scheduler2[F[_, _]] extends BootstrapRuntime {
def repeat[E, A, B](eff: F[E, A])(schedule: Schedule[Clock, A, B]): F[E, B]
}
object Scheduler2 {
def apply[F[+_, +_] : Scheduler2]: Scheduler2[F] = implicitly
implicit def fromZIO: Scheduler2[IO] = new Scheduler2[IO] {
override def repeat[E, A, B](eff: IO[E, A])(schedule: Schedule[Clock, A, B]): IO[E, B] = {
eff.repeat(schedule).provide(environment)
}
}
}
object Main extends scala.App {
val rt = Runtime.default
implicit val a: Layer[Nothing, Clock] = Clock.live
def repeatEffectTF[F[+_, +_]: IO2: Scheduler2]: F[Nothing, Long] =
Scheduler2[F].repeat(F.sync(println("Effect TF")))(Schedule.spaced(3.second))
rt.unsafeRun(repeatEffectTF[zio.IO])
}
trait Scheduler2[F[_, _]] extends BootstrapRuntime {
def repeat[E, A, B](eff: F[E, A])(schedule: Schedule[Clock, A, B]): F[E, B]
}
object Scheduler2 {
def apply[F[+_, +_] : Scheduler2]: Scheduler2[F] = implicitly
implicit def fromZIO: Scheduler2[IO] = new Scheduler2[IO] {
override def repeat[E, A, B](eff: IO[E, A])(schedule: Schedule[Clock, A, B]): IO[E, B] = {
eff.repeat(schedule).provide(environment)
}
}
implicit class syntax[F[+_, +_]: IO2: Scheduler2, E, A, B](eff: F[E, A]) {
def zioRepeat(schedule: Schedule[Clock, A, B]) =
Scheduler2[F].repeat(eff)(schedule)
}
}
object Main extends scala.App {
val rt = Runtime.default
implicit val a: Layer[Nothing, Clock] = Clock.live
import Scheduler2.syntax
def repeatEffectTF[F[+_, +_]: IO2: Scheduler2]: F[Nothing, Long] =
Scheduler2[F].repeat(F.sync(println("Effect TF")))(Schedule.spaced(3.second))
def repeatEffectTF2[F[+_, +_]: IO2: Scheduler2]: F[Nothing, Long] =
F.sync(println("Effect TF")).zioRepeat(Schedule.spaced(3.second))
rt.unsafeRun(repeatEffectTF2[zio.IO])
}
Run sbtgen.sc
actions and worked correctly before 🤔 Should work fine after 7mind/izumi#1534 I've also submitted an upstream issue https://youtrack.jetbrains.com/issue/SCL-19212
Hi good Izumi folks! I'm bumping versions in my application (ZIO+Http4s+Tapir+Distage) and got some problems. I saw that Cats effect 3 is not supported yet so I've made sure to only use dependencies using CE2. However, I seem to get some issue with distage-extension-config
and magnolia
I think. The only other dependency using magnolia is tapir-core which I have at version 0.18.3
. I can't find any version conflict that would explain the java.lang.NoSuchMethodError
.
Not sure if it is related, but I also changed my main Role to extend RoleService[RIO[ZEnv, +*]]
instead of RoleService[Task]
.
Found a problem with your DI wiring, when checking application=MainProd, with parameters:
[error]
[error] roles = * (effective: unknown, failed too early)
[error] excludedActivations = ø
[error] bootstrapPlugins = ø
[error] plugins = ø
[error] checkConfig = false
[error] printBindings = false, set to `true` for full bindings printout
[error] onlyWarn = false, set to `true` to ignore compilation error
[error]
[error] You may may turn this error into a warning by setting system property in sbt, `sbt -Dizumi.distage.plancheck.only-warn=true` or by adding the option to `.jvmopts` in project root.
[error]
[error] Error was:
[error]
[error] izumi.distage.model.exceptions.ProvisioningException: Provisioner failed on 1 of 38 required operations, just 26 succeeded:
[error] - {type.izumi.distage.plugins.load.LoadedPlugins@main} (RoleAppBootModule.scala:111), java.lang.NoSuchMethodError: java.lang.NoSuchMethodError: magnolia.Param$.apply(Ljava/lang/String;IZLmagnolia/CallByNeed;Lmagnolia/CallByNeed;[Ljava/lang/Object;[Ljava/lang/Object;)Lmagnolia/Param;
[error] at <first line in a ConfigModuleDef using makeConfig, e.g. makeConfig[PostgresConfig]("pg")>
[error] at sun.misc.Unsafe.ensureClassInitialized(Native Method)
[error] at sun.reflect.UnsafeFieldAccessorFactory.newFieldAccessor(UnsafeFieldAccessorFactory.java:43)
[error] at sun.reflect.ReflectionFactory.newFieldAccessor(ReflectionFactory.java:156)
[error] at java.lang.reflect.Field.acquireFieldAccessor(Field.java:1088)
[error] at java.lang.reflect.Field.getFieldAccessor(Field.java:1069)
[error] at java.lang.reflect.Field.get(Field.java:393)
[error] at izumi.distage.plugins.load.PluginLoaderDefaultImpl$.$anonfun$doLoad$9(PluginLoaderDefaultImpl.scala:74)
...
Maybe you see something I don't? :)
sbt dependencyBrowseTree
I don't see anything obviously wrong. Could I be missing something due to No More Orphans approach? // sbt dependencyBrowseTree magnolia in working version
com.softwaremill.sttp.tapir:tapir-core_2.13:0.13.2
com.propensive:magnolia_2.13:0.14.1 (evicted by 0.17.0)
com.propensive:magnolia_2.13:0.17.0
io.7mind.izumi:distage-extension-config_2.13:1.0.5
com.github.pureconfig:pureconfig-magnolia_2.13:0.14.1
com.github.pureconfig:pureconfig-core_2.13:0.14.1
com.github.pureconfig:pureconfig-generic-base_2.13:0.14.1
com.propensive:magnolia_2.13:0.17.0
// sbt dependencyBrowseTree magnolia in broken version
com.softwaremill.sttp.tapir:tapir-core_2.13:0.16.16
com.propensive:magnolia_2.13:0.16.0 (evicted by 0.17.0)
com.propensive:magnolia_2.13:0.17.0
io.7mind.izumi:distage-extension-config_2.13:1.0.8
com.github.pureconfig:pureconfig-magnolia_2.13:0.16.0
com.github.pureconfig:pureconfig-core_2.13:0.16.0
com.github.pureconfig:pureconfig-generic-base_2.13:0.16.0
com.propensive:magnolia_2.13:0.17.0
com.propensive:magnolia_2.13:0.17.0
@Edvin-san Hmm, this actually can't be related to softwaremill/magnoila since they use a different package name:
The main magnolia package is magnolia1, so that magnolia 1.x can be used alongside magnolia 0.17 (which are binary-incompatible). Future major releases of magnolia can change the package name for the same reason.
I wonder if the problem is opposite: one of the dependencies using a very old version of magnolia, incompatible with 0.17.0 ...
Also, maybe you just need to explicitly add a Runtime
(regular) dependency on magnolia into the module in which you placed the compile-time check code – maybe the magnolia version is fine, but the checker in the course of collecting bindings is evaluating object
s that force execution of magnolia code at runtime while magnolia may be a Provided
or Optional
dependency - not on the runtime classpath.
Hi, I am new to distage and was following the documentation and example application to build a small POC based on cats effect's Sync type class, but I am hitting a wall using TagK in my PluginDef. Maybe someone can point me towards a solution here.
[error] App.scala:20:13: could not find implicit value for evidence parameter of type distage.TagK[F]
[error] include(rideRelationCapacities)
[error] ^
[error] App.scala:26:9: parameter value evidence$2 in method rideRelationCapacities is never used
[error] def rideRelationCapacities[F[_]: TagK: Async]: ModuleDef = new ModuleDef {
[error] ^
[error] two errors found
[error] (ride-relation-projection / Compile / compileIncremental) Compilation failed
This is the PluginDef:
object AppPlugin extends PluginDef {
include(roleModule)
include(rideRelationCapacities)
def roleModule: RoleModuleDef = new RoleModuleDef {
makeRole[RideRelationCapacityService]
}
def rideRelationCapacities[F[_]: TagK: Async]: ModuleDef = new ModuleDef {
make[RideRelationCapacities[F]]
.fromResource[RideRelationCapacities.Dummy[F]]
.tagged(Repo.Dummy)
}
}
And for completeness the Dummy repository implementation:
trait RideRelationCapacities[F[_]] {
def add(rideRelationCapacities: NonEmptySeq[RideRelationCapacity]): F[Unit]
def get(rideId: UUID): F[Option[NonEmptySeq[RideRelationCapacity]]]
def rel(rideId: UUID, fromId: UUID, toId: UUID): F[Option[RideRelationCapacity]]
}
object RideRelationCapacities {
final class Dummy[F[_]: Sync]
extends Lifecycle.LiftF[F, RideRelationCapacities[F]](for {
state <- Sync[F].pure(Map.empty[(UUID, UUID, UUID), Int])
} yield {
new RideRelationCapacities[F] {
type Item = ((UUID, UUID, UUID), Int)
private var s = state
private def tupled(i: Item): RideRelationCapacity = RideRelationCapacity(i._1._1, i._1._2, i._1._3, i._2)
override def add(rideRelationCapacities: NonEmptySeq[RideRelationCapacity]): F[Unit] =
rideRelationCapacities.traverse_(rc =>
Sync[F].delay {
s = s.updated((rc.rideId, rc.from, rc.to), rc.capacity)
},
)
override def get(rideId: UUID): F[Option[NonEmptySeq[RideRelationCapacity]]] =
Sync[F].pure {
val filtered = s.filter(_._1._1 === rideId)
if (filtered.isEmpty) None else Some(NonEmptySeq.fromSeqUnsafe(s.map(tupled).toSeq))
}
override def rel(rideId: UUID, fromId: UUID, toId: UUID): F[Option[RideRelationCapacity]] =
Sync[F].pure(
s.find(rc => rc._1._1 == rideId && rc._1._2 == fromId && rc._1._3 == toId)
.map(tupled),
)
}
})
}
@tPl0ch
Vlad means that in final class Dummy[F[_]: Sync]
the Sync
bound is not actually satisfied from Async
in def rideRelationCapacities[F[_]: TagK: Async]
- if you remove the Async
here, it will still work.
Surrounding implicits are not used when a class is built using make[X]
or make[X].from[Y]
, instead all parameters of classes, including implicit are passed from distage. (You may use surrounding implicits in expressions such as make[X].from { implicitly[XY].doSomething }
, but instead you're encouraged to add them as distage components and summon them from there, not from implicit scope)
Async[F] is found by distage because the cats-effect hierarchy is available by default – for convenience – whenever running distage using an effect type that implements cats-effect typeclasses. (You may find this feature documented here – https://izumi.7mind.io/distage/basics.html#out-of-the-box-typeclass-instances)
Hi! I had to pause my upgrade of dependencies for a while but now I've started looking at it again. I think I found some unrelated issues, one is relating to changing the effect type of my main role to ZIO[ZEnv, Throwable, +*]
.
My launcher is
object Launcher extends RoleAppMain.LauncherBIO3[ZIO]
type MyEff[+A] = RIO[ZEnv, A]
class MyRole(...) extends RoleService[MyEff]
// in plugins
val roles: RoleModuleDef = new RoleModuleDef {
makeRole[MyRole]
include(BundledRolesModule[MyEff](version = "1.0.0"))
}
I get the following logs when trying to launch using this role
W 2021-11-25T11:05:15.380 (RoleProvider.scala:94) …Provider.Impl.checkRoleType [1:main] phase=early Found role binding with incompatible effect type implType=izumi.distage.roles.bundled.ConfigWriter[=λ %0 → ZIO[-{Has[=package::System::Service] & Has[=package::Clock::Service] & Has[=package::Random::Service] & Has[=package::Blocking::Service] & Has[=package::Console::Service]},+Throwable,+0]] (expected to be a subtype of roleType=izumi.distage.roles.model.AbstractRole[+λ %2 → ZIO[-Any,+Throwable,+2]])
"com.spotify" %% "magnolify-scalacheck" % "0.4.4" % Test
which seems to have caused the issue. We downgraded it to "0.2.3" which uses com.propensive
v "0.17.0". I don't completely understand why it was binary incompatible but for completeness I thought I'd share it here.
@Edvin-san
Well, the softwaremill jar they depend on does overwrite magnolia package:
> amm
@ import $ivy.`com.softwaremill.magnolia:magnolia-core_2.13:1.0.0-M4`
Downloading https://repo1.maven.org/maven2/com/softwaremill/magnolia/magnolia-core_2.13/1.0.0-M4/magnolia-core_2.13-1.0.0-M4.pom
Downloaded https://repo1.maven.org/maven2/com/softwaremill/magnolia/magnolia-core_2.13/1.0.0-M4/magnolia-core_2.13-1.0.0-M4.pom
Downloading https://repo1.maven.org/maven2/org/scala-lang/scala-compiler/2.13.0/scala-compiler-2.13.0-sources.jar
Downloading https://repo1.maven.org/maven2/com/softwaremill/magnolia/magnolia-core_2.13/1.0.0-M4/magnolia-core_2.13-1.0.0-M4-sources.jar
Downloading https://repo1.maven.org/maven2/com/softwaremill/magnolia/magnolia-core_2.13/1.0.0-M4/magnolia-core_2.13-1.0.0-M4.jar
Downloaded https://repo1.maven.org/maven2/com/softwaremill/magnolia/magnolia-core_2.13/1.0.0-M4/magnolia-core_2.13-1.0.0-M4-sources.jar
Downloaded https://repo1.maven.org/maven2/org/scala-lang/scala-compiler/2.13.0/scala-compiler-2.13.0-sources.jar
Downloaded https://repo1.maven.org/maven2/com/softwaremill/magnolia/magnolia-core_2.13/1.0.0-M4/magnolia-core_2.13-1.0.0-M4.jar
import $ivy.$
@ import magnolia.Magnolia
import magnolia.Magnolia
@ Magnolia
res2: Magnolia.type = magnolia.Magnolia$@750ff7d3
I would guess that they added new methods (which causes breakage when code compiled with softwaremill magnolia tries to run with propensive magnolia jar), but most likely didn't break the old ones, so Instead of downgrading the dependency, you could filter out propensive magnolia by adding it globally to excludeDependencies
and adding the softwaremill jar instead, that would allow using the latest version of that magnolify-scalacheck library.
ThisBuild / excludeDependencies += "com.propensive" %% "magnolia" % "0.17.0"
ThisBuild / libraryDependencies += "com.softwaremill.magnolia" %% "magnolia-core" % "1.0.0-M4"
@neko-kai Thanks for your reply and clearing that up for me.
I am pretty sure that I am not going to use purely tagless final style code for generalizing streams anyways, because I have tried that and the type signatures of everything get absolutely gigantic.
But I thought that it could not hurt to ask around here because the code I have seen from izumi looked like it could help me out and I'd happily take a ready-made solution over writing my own.
Tofu looks interesting, I had heard of it before, but I have last seen it some years ago, so it did not occur to me to check it out again.
It's basically a more user focused tagless-final library without all the complexity that the typeclasses from cats-effect bring with them, right?
Hello, I've got a question about logstage. With zio-logging, log context is passed by utilizing FiberRef. I would ideally want to use logstage's LogZIO in the same way and not pass it through the environment type.
2.
I also have a concrete example where it would be useful, I would like to add contextual logging to my Http4s Client. So far I've done like this:
make[Client[Task]].fromResource {
(CE: ConcurrentEffect[Task], ec: ExecutionContext @Id("zio.io"), log: LogIO2[IO]) =>
val logAction: String => UIO[Unit] = (s: String) => log.raw.debug(s)
BlazeClientBuilder[Task](ec)(CE)
.resource
.map(Logger(logBody = true, logHeaders = true, logAction = Some(logAction)))
}
But I lose the context because I've not been able to propagate it to the logAction in the client.
Any advice on how to proceed?
logstage.LogZIO
object - https://github.com/7mind/izumi/blob/c59e662c62de5bfe312edc42341626c87f6c46c4/logstage/logstage-core/src/main/scala/logstage/LogZIO.scala#L45 - withDynamicContext
will let you read the context from a FiberRef or obtain it any other way.
LogZIO.log
to use the contextual logger (https://izumi.7mind.io/latest/snapshot/logstage/index.html#zio-environment-support - snapshot doc is more up to date than release, I'm not sure if there are methods in the examples that weren't yet released in 1.0.8
, but I think not)
IzLogger
's .customContext
method. Note that .withCustomContext
/.apply
append to the existing context, not replace it, so if you just need to append/update you don't need to retrieve the existing context.