【问题标题】:Cadence Workflow ZonedDateTime Args Zone ID ConversionCadence 工作流程 ZonedDateTime Args 区域 ID 转换
【发布时间】:2021-11-08 07:02:08
【问题描述】:

我有一个以 UTC 的 ZonedDatetime 作为参数的工作流程。在使用测试环境进行单元测试期间,我看到 UTC 区域在运行工作流时被删除。这种行为的原因是什么?

[UPDATE] 事实证明,时区并没有被删除,而是以某种方式转换为“Z”的区域 id 而不是原来的“UTC”,尽管它们基本相同。示例代码,

data class WorkflowArgs(
   val currentTime: ZonedDateTime
)

class WorkflowImpl {
    override fun execute(workflowArgs: WorkflowArgs) { 
     activityStub.doSomeActivity(
         workflowArgs.currentTime // Zone ID of "Z"
     )
    }
}

WorkflowClient.start(workflowStub::execute, WorkflowArgs(ZonedDateTime.now(ZoneId.of("UTC")))  // Zone ID of "UTC"

【问题讨论】:

  • 可能是数据转换器的原因。您使用的是哪个客户端 SDK?并展示了如何传递参数的示例代码?
  • 谢谢@LongQuanzheng 我用示例代码更新了问题,你提到的数据转换是什么?
  • 这是因为 ZonedDateTime 不适用于默认的 JSON 序列化。你需要自己实现它。我添加了一个帮助答案。

标签: cadence-workflow


【解决方案1】:

您需要自定义DataConverter

DataConvert 用于在您的参数(类)和字节数组之间进行转换,以便您的客户端可以将参数发送到 Cadence 服务器,然后服务器将其发送到工作流工作者。

例如,您可以执行以下操作。

请注意,这只是您实现 DataConverter 的示例。要对 ZonedDataTime 进行编码/解码,您需要找到一种正确执行此操作的方法。您可能需要参考Spring Data JPA - ZonedDateTime format for json serialization


data class WorkflowArgs(
    val currentTime: ZonedDateTime
)

fun main1() { // this doesn't work
    val dataConverter = JsonDataConverter.getInstance()
    val args = WorkflowArgs( ZonedDateTime.now())
    println(args.currentTime.zone)
    val encoded = dataConverter.toData(args)
    val decoded: WorkflowArgs = dataConverter.fromData(encoded, args.javaClass, args.javaClass)
    println(decoded.currentTime.zone)
    /**
     * Results:
    America/Los_Angeles
    Exception in thread "main" com.uber.cadence.converter.DataConverterException: when parsing:"{"currentTime":{"dateTime":{"date":{"year":2021,"month":9,"day":13},"time":{"hour":9,"minute":14,"second":46,"nano":517000000}},"offset":{"totalSeconds":-25200},"zone":{"id":"America/Los_Angeles"}}}" into following types: [class com.uber.cadence.converter.WorkflowArgs]
    at com.uber.cadence.converter.JsonDataConverter.fromData(JsonDataConverter.java:111)
    at com.uber.cadence.converter.TestZonedDatatimeKt.main(TestZonedDatatime.kt:14)
    at com.uber.cadence.converter.TestZonedDatatimeKt.main(TestZonedDatatime.kt)
    Caused by: java.lang.RuntimeException: Failed to invoke java.time.ZoneId() with no args
    at com.google.gson.internal.ConstructorConstructor$3.construct(ConstructorConstructor.java:113)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:212)
...
    at com.uber.cadence.converter.JsonDataConverter.fromData(JsonDataConverter.java:109)
    ... 2 more
     */
}

fun main() { // you need to implement another DataConverter like this
    val dataConverter = MyDataConvert()
    val args = WorkflowArgs( ZonedDateTime.now())
    println(args.currentTime.zone)
    val encoded = dataConverter.toData(args)
    val decoded: WorkflowArgs = dataConverter.fromData(encoded, args.javaClass, args.javaClass)
    println(decoded.currentTime.zone)
/**
Resutls:
America/Los_Angeles
America/Los_Angeles
**/
}

class MyDataConvert:DataConverter{

    val originalDataConverter = JsonDataConverter.getInstance()

    override fun toData(vararg value: Any?): ByteArray {
        if( (value.size == 1) && (value[0] is WorkflowArgs)){
            val v = value[0] as WorkflowArgs
            val zoneId = v.currentTime.zone.id
            val br = zoneId.toByteArray()
            return br
        }else{
            return originalDataConverter.toData(value)
        }
    }

    override fun <T : Any?> fromData(content: ByteArray?, valueClass: Class<T>?, valueType: Type?): T {
        if(valueClass!!.canonicalName.contains("WorkflowArgs") ){
            val zi = String(content!!)
            val zoneId: ZoneId = ZoneId.of(zi)
            val dt = ZonedDateTime.now(zoneId)
            return WorkflowArgs(dt) as T
        }else{
            return originalDataConverter.fromData(content, valueClass, valueType)
        }
    }

    override fun fromDataArray(content: ByteArray?, vararg valueType: Type?): Array<Any> {
        if( (valueType.size == 1) && (valueType[0]!!.typeName.contains("WorkflowArgs"))){
            val zi = String(content!!)
            val zoneId: ZoneId = ZoneId.of(zi)
            val dt = ZonedDateTime.now(zoneId)
            val arr = arrayOf(WorkflowArgs(dt))
            return arr as Array<Any>
        }
        return originalDataConverter.fromDataArray(content, *valueType)
    }

}


这是另一个实现 DataConverter 的示例:https://github.com/uber/cadence-java-samples/pull/37

【讨论】:

  • 我明白了。谢谢你的例子。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-29
  • 2020-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多