temporalio / sdk-java

Temporal Java SDK
https://temporal.io
Apache License 2.0
213 stars 143 forks source link

Scala module #1007

Open doruchiulan opened 4 years ago

doruchiulan commented 4 years ago

I'll go with a top-to-bottom approach with the things I encountered, and how I tried to solve them in my project.

  1. WorkflowClient
    • WorkflowClient.start with io.temporal.workflow.Functions.Func arguments
    • WorkflowClient.start with io.temporal.workflow.Functions.Proc arguments
    • WorkflowClient.execute with io.temporal.workflow.Functions.Func arguments
    • WorkflowClient.execute with io.temporal.workflow.Functions.Proc arguments

Solved this by writing some small wrappers. I don't think this is the way, but the code inside might be useful. These are the only type of functions I needed, didn't convert them all (e.g the ones that take more arguments)

def startAsync(f: T => Unit, arg: T): WorkflowExecution = {
    WorkflowClient.start(new Proc1[T]() {
      override def apply(j: T): Unit = f(j)
    }, t)
  }

  def executeAsyncVoid(f: () => Unit): Future[Unit] = {
    import scala.compat.java8.FutureConverters._

    WorkflowClient.execute(new Proc {
      override def apply(): Unit = f()
    }).toScala.map[Unit](_ => ())
  }

  def executeAsync[T](f: () => T): Future[T] = {
    import scala.compat.java8.FutureConverters._

    WorkflowClient.execute(new Func[T] {
      override def apply(): T = f()
    }).toScala
  }
  1. Scala specific object types serialization/deserialization

    • Option
    • List (basically all Scala collections)

We can probably solve this when Jackson will be integrated in java-sdk

  1. Workflow.await requiring a Supplier, instead of passing a function reference

Again, solved in a simple wrapper

 def await(duration: Duration, f: () => Boolean) {
    Workflow.await(duration, new Supplier[lang.Boolean] {
      override def get(): lang.Boolean = f()
    })
  }
  1. Java way of referencing some method (not sure how this syntax it's called in Java) (Mostly the same as 1. but I put it in a different issue as it's a little bit a different problem)

WorkflowClient.execute(workflow::getGreeting, "World") -> notice the double colon

  1. Accepting Scala Duration type
Krever commented 4 years ago

Hey, we have some experience in using cadence with scala and can contribute our experiences and maybe even some code.

Reg 2) Serialization is a tough topic, in general, typeclass-based serialization is more idiomatic and safer in modern scala. But this would be something to have in scala native sdk and so is out of the scope of this issue probably.

1 & 3 are already solved in scala 2.12 and later -> https://www.scala-lang.org/news/2.12.0/#lambda-syntax-for-sam-types

2 & 5 as proposed are not possible without adding scala stdlib as a dependency of java sdk, which doesn't sound plausible. Whereas 2) Is quite hard, the 5) is easily solved by https://github.com/scala/scala-java8-compat#converters-between-scalaconcurrentdurationfiniteduration-and-javatimeduration

grouzen commented 3 years ago

Hello!

Just wondering about the progress with scala-sdk for Temporal? Any updates?

doruchiulan commented 3 years ago

Not really using cadence in my current projects, but I'm still keeping an eye on this as this is a project which I really like and which I will happily include in any project that suits it. So if somebody takes over, has a plan/architecture and leads this, I will happily contribute with pieces of code.

jvican commented 2 years ago

Hi. Really interested in helping this move forward by creating an integration. Is there a guide I can use to start making the integration possible?

ktham commented 2 years ago

Would love the additional support for Scala 👍 it could potentially unlock some interesting use-cases if I can pitch Temporal to my team

vitaliihonta commented 2 years ago

Hi everyone I’ve implemented Scala SDK, which supports most temporal features. https://github.com/vitaliihonta/zio-temporal

It also allows using protobuf format via ScalaPB.

Currently, it’s tied to ZIO

scoplin commented 2 years ago

I got bit by a problem with the reflection logic that attempts to determine whether Async.function is being passed a method reference in MethodReferenceDisassembler#isAsyncJava. Turns out that a method reference in Scala has a different result from getImplMethodKind. It returns MethodHandleInfo.REF_invokeStatic instead of MethodHandleInfo.REF_invokeInterface. We had to invoke this through a small java shim to get it to function correctly and not execute directly on the local workflow executor.

I think ztemporal may have the same problem. It also appears to me to call Async.function passing a Scala lambda expression.