All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.zeebe.test.broker.protocol.commandapi.PartitionTestClient Maven / Gradle / Ivy

/*
 * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under
 * one or more contributor license agreements. See the NOTICE file distributed
 * with this work for additional information regarding copyright ownership.
 * Licensed under the Zeebe Community License 1.0. You may not use this file
 * except in compliance with the Zeebe Community License 1.0.
 */
package io.zeebe.test.broker.protocol.commandapi;

import static io.zeebe.protocol.record.intent.JobIntent.ACTIVATED;
import static io.zeebe.test.util.TestUtil.doRepeatedly;
import static io.zeebe.util.buffer.BufferUtil.bufferAsString;
import static org.assertj.core.api.Assertions.assertThat;

import io.zeebe.model.bpmn.Bpmn;
import io.zeebe.model.bpmn.BpmnModelInstance;
import io.zeebe.model.bpmn.builder.ServiceTaskBuilder;
import io.zeebe.protocol.Protocol;
import io.zeebe.protocol.impl.record.value.deployment.DeploymentRecord;
import io.zeebe.protocol.impl.record.value.deployment.Workflow;
import io.zeebe.protocol.impl.record.value.job.JobBatchRecord;
import io.zeebe.protocol.impl.record.value.job.JobRecord;
import io.zeebe.protocol.impl.record.value.message.MessageRecord;
import io.zeebe.protocol.impl.record.value.workflowinstance.WorkflowInstanceCreationRecord;
import io.zeebe.protocol.record.Record;
import io.zeebe.protocol.record.RecordType;
import io.zeebe.protocol.record.ValueType;
import io.zeebe.protocol.record.intent.DeploymentIntent;
import io.zeebe.protocol.record.intent.IncidentIntent;
import io.zeebe.protocol.record.intent.Intent;
import io.zeebe.protocol.record.intent.JobBatchIntent;
import io.zeebe.protocol.record.intent.JobIntent;
import io.zeebe.protocol.record.intent.MessageIntent;
import io.zeebe.protocol.record.intent.TimerIntent;
import io.zeebe.protocol.record.intent.VariableDocumentIntent;
import io.zeebe.protocol.record.intent.WorkflowInstanceCreationIntent;
import io.zeebe.protocol.record.intent.WorkflowInstanceIntent;
import io.zeebe.protocol.record.value.BpmnElementType;
import io.zeebe.protocol.record.value.DeploymentRecordValue;
import io.zeebe.protocol.record.value.IncidentRecordValue;
import io.zeebe.protocol.record.value.JobRecordValue;
import io.zeebe.protocol.record.value.MessageRecordValue;
import io.zeebe.protocol.record.value.TimerRecordValue;
import io.zeebe.protocol.record.value.VariableDocumentUpdateSemantic;
import io.zeebe.protocol.record.value.WorkflowInstanceRecordValue;
import io.zeebe.protocol.record.value.deployment.ResourceType;
import io.zeebe.test.util.MsgPackUtil;
import io.zeebe.test.util.TestUtil;
import io.zeebe.test.util.record.DeploymentRecordStream;
import io.zeebe.test.util.record.IncidentRecordStream;
import io.zeebe.test.util.record.JobBatchRecordStream;
import io.zeebe.test.util.record.JobRecordStream;
import io.zeebe.test.util.record.MessageRecordStream;
import io.zeebe.test.util.record.MessageSubscriptionRecordStream;
import io.zeebe.test.util.record.RecordingExporter;
import io.zeebe.test.util.record.TimerRecordStream;
import io.zeebe.test.util.record.WorkflowInstanceRecordStream;
import io.zeebe.test.util.record.WorkflowInstanceSubscriptionRecordStream;
import io.zeebe.util.buffer.BufferUtil;
import io.zeebe.util.buffer.BufferWriter;
import io.zeebe.util.collection.Tuple;
import java.io.ByteArrayOutputStream;
import java.time.Duration;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import org.agrona.DirectBuffer;

public final class PartitionTestClient {
  // workflow related properties

  public static final String PROP_WORKFLOW_RESOURCES = "resources";
  public static final String PROP_WORKFLOW_VERSION = "version";
  public static final String PROP_WORKFLOW_VARIABLES = "variable";
  public static final String PROP_WORKFLOW_INSTANCE_KEY = "workflowInstanceKey";
  public static final String PROP_WORKFLOW_KEY = "workflowKey";

  private final CommandApiRule apiRule;
  private final int partitionId;

  public PartitionTestClient(final CommandApiRule apiRule, final int partitionId) {
    this.apiRule = apiRule;
    this.partitionId = partitionId;
  }

  public long deploy(final BpmnModelInstance workflow) {
    final ExecuteCommandResponse response = deployWithResponse(workflow);

    assertThat(response.getRecordType())
        .withFailMessage("Deployment failed: %s", response.getRejectionReason())
        .isEqualTo(RecordType.EVENT);

    final long key = response.getKey();

    TestUtil.waitUntil(
        () ->
            RecordingExporter.deploymentRecords(DeploymentIntent.DISTRIBUTED)
                .withRecordKey(key)
                .exists());

    return key;
  }

  public ExecuteCommandResponse deployWithResponse(final byte[] resource) {
    return deployWithResponse(resource, "BPMN_XML", "process.bpmn");
  }

  public ExecuteCommandResponse deployWithResponse(final BpmnModelInstance workflow) {
    return deployWithResponse(workflow, "process.bpmn");
  }

  public ExecuteCommandResponse deployWithResponse(
      final BpmnModelInstance workflow, final String resourceName) {
    final ByteArrayOutputStream outStream = new ByteArrayOutputStream();
    Bpmn.writeModelToStream(outStream, workflow);
    final byte[] resource = outStream.toByteArray();

    return deployWithResponse(resource, "BPMN_XML", resourceName);
  }

  public ExecuteCommandResponse deployWithResponse(
      final byte[] resource, final String resourceType, final String resourceName) {
    final Map deploymentResource = new HashMap<>();
    deploymentResource.put("resource", resource);
    deploymentResource.put("resourceType", resourceType);
    deploymentResource.put("resourceName", resourceName);

    final ExecuteCommandResponse commandResponse =
        apiRule
            .createCmdRequest()
            .partitionId(Protocol.DEPLOYMENT_PARTITION)
            .type(ValueType.DEPLOYMENT, DeploymentIntent.CREATE)
            .command()
            .put(PROP_WORKFLOW_RESOURCES, Collections.singletonList(deploymentResource))
            .put("resourceType", resourceType)
            .done()
            .sendAndAwait();

    return commandResponse;
  }

  public Workflow deployWorkflow(final BpmnModelInstance workflow) {
    final DeploymentRecord request = new DeploymentRecord();
    final ByteArrayOutputStream outStream = new ByteArrayOutputStream();
    Bpmn.writeModelToStream(outStream, workflow);

    request
        .resources()
        .add()
        .setResource(outStream.toByteArray())
        .setResourceName("process.bpmn")
        .setResourceType(ResourceType.BPMN_XML);

    final DeploymentRecord response = deploy(request);
    final Iterator iterator = response.workflows().iterator();
    assertThat(iterator).as("Expected at least one deployed workflow, but none returned").hasNext();

    return iterator.next();
  }

  public DeploymentRecord deploy(final Function transformer) {
    return deploy(transformer.apply(new DeploymentRecord()));
  }

  public DeploymentRecord deploy(final DeploymentRecord request) {
    final ExecuteCommandResponse response =
        executeCommandRequest(ValueType.DEPLOYMENT, DeploymentIntent.CREATE, request);

    assertThat(response.getRecordType()).isEqualTo(RecordType.EVENT);
    assertThat(response.getIntent()).isEqualTo(DeploymentIntent.CREATED);

    return response.readInto(new DeploymentRecord());
  }

  public WorkflowInstanceCreationRecord createWorkflowInstance(
      final Function mapper) {
    return createWorkflowInstance(mapper.apply(new WorkflowInstanceCreationRecord()));
  }

  public WorkflowInstanceCreationRecord createWorkflowInstance(
      final WorkflowInstanceCreationRecord record) {
    final ExecuteCommandResponse response =
        executeCommandRequest(
            ValueType.WORKFLOW_INSTANCE_CREATION, WorkflowInstanceCreationIntent.CREATE, record);

    assertThat(response.getRecordType()).isEqualTo(RecordType.EVENT);
    assertThat(response.getIntent()).isEqualTo(WorkflowInstanceCreationIntent.CREATED);

    return response.readInto(new WorkflowInstanceCreationRecord());
  }

  public ExecuteCommandResponse executeCommandRequest(
      final ValueType valueType, final Intent intent, final BufferWriter command) {
    return executeCommandRequest(valueType, intent, command, -1);
  }

  public ExecuteCommandResponse executeCommandRequest(
      final ValueType valueType, final Intent intent, final BufferWriter command, final long key) {
    return apiRule
        .createCmdRequest()
        .partitionId(partitionId)
        .key(key)
        .type(valueType, intent)
        .command(command)
        .sendAndAwait();
  }

  public ExecuteCommandResponse cancelWorkflowInstance(final long key) {
    return apiRule
        .createCmdRequest()
        .partitionId(partitionId)
        .type(ValueType.WORKFLOW_INSTANCE, WorkflowInstanceIntent.CANCEL)
        .key(key)
        .command()
        .done()
        .sendAndAwait();
  }

  public void updateVariables(final long scopeKey, final Map document) {
    updateVariables(scopeKey, VariableDocumentUpdateSemantic.PROPAGATE, document);
  }

  public void updateVariables(
      final long scopeKey,
      final VariableDocumentUpdateSemantic updateSemantics,
      final Map document) {
    final ExecuteCommandResponse response =
        apiRule
            .createCmdRequest()
            .type(ValueType.VARIABLE_DOCUMENT, VariableDocumentIntent.UPDATE)
            .command()
            .put("scopeKey", scopeKey)
            .put("updateSemantics", updateSemantics)
            .put("document", MsgPackUtil.asMsgPack(document).byteArray())
            .done()
            .sendAndAwait();

    assertThat(response.getRecordType()).isEqualTo(RecordType.EVENT);
    assertThat(response.getIntent()).isEqualTo(VariableDocumentIntent.UPDATED);
  }

  public long createJob(final String type) {
    return createJob(type, b -> {}, "{}");
  }

  public long createJob(
      final String type, final Consumer consumer, final String variables) {
    deploy(
        Bpmn.createExecutableProcess("process")
            .startEvent()
            .serviceTask(
                "task",
                b -> {
                  b.zeebeJobType(type).zeebeJobRetries("3");
                  consumer.accept(b);
                })
            .done());

    final long workflowInstance =
        createWorkflowInstance(
                r -> r.setBpmnProcessId("process").setVariables(MsgPackUtil.asMsgPack(variables)))
            .getWorkflowInstanceKey();

    return RecordingExporter.jobRecords(JobIntent.CREATED)
        .withType(type)
        .filter(j -> j.getValue().getWorkflowInstanceKey() == workflowInstance)
        .getFirst()
        .getKey();
  }

  public JobRecord activateAndCompleteFirstJob(
      final String jobType, final Predicate filter) {
    final Tuple pair = activateJob(jobType, filter);
    return completeJob(pair.getLeft(), pair.getRight());
  }

  public Tuple activateJob(
      final String jobType, final Predicate filter) {
    final JobBatchRecord request =
        new JobBatchRecord()
            .setType(jobType)
            .setMaxJobsToActivate(1)
            .setTimeout(1000)
            .setWorker("partition-" + partitionId + "-" + jobType);

    return doRepeatedly(
            () -> {
              final JobBatchRecord response = activateJobBatch(request);
              if (response.getMaxJobsToActivate() > 0) {
                final JobRecord job = response.jobs().iterator().next();
                if (filter.test(job)) {
                  return new Tuple<>(response.jobKeys().iterator().next().getValue(), job);
                }
              }

              return null;
            })
        .until(Objects::nonNull);
  }

  public JobRecord completeJob(
      final long jobKey, final Function transformer) {
    return completeJob(jobKey, transformer.apply(new JobRecord()));
  }

  public JobRecord completeJob(final long jobKey, final JobRecord request) {
    final ExecuteCommandResponse response =
        executeCommandRequest(ValueType.JOB, JobIntent.COMPLETE, request, jobKey);

    assertThat(response.getRecordType()).isEqualTo(RecordType.EVENT);
    assertThat(response.getIntent()).isEqualTo(JobIntent.COMPLETED);
    return response.readInto(new JobRecord());
  }

  public JobBatchRecord activateJobBatch(
      final Function transformer) {
    return activateJobBatch(transformer.apply(new JobBatchRecord()));
  }

  public JobBatchRecord activateJobBatch(final JobBatchRecord request) {
    final ExecuteCommandResponse response =
        executeCommandRequest(ValueType.JOB_BATCH, JobBatchIntent.ACTIVATE, request);

    assertThat(response.getRecordType()).isEqualTo(RecordType.EVENT);
    assertThat(response.getIntent()).isEqualTo(JobBatchIntent.ACTIVATED);
    return response.readInto(new JobBatchRecord());
  }

  public void completeJobOfType(final long workflowInstanceKey, final String jobType) {
    completeJob(
        jobType,
        MsgPackUtil.asMsgPackReturnArray("{}"),
        r -> r.getValue().getWorkflowInstanceKey() == workflowInstanceKey);
  }

  public void completeJobOfType(final String jobType) {
    completeJobOfType(jobType, "{}");
  }

  public void completeJobOfType(final String jobType, final byte[] variables) {
    completeJob(jobType, variables, e -> true);
  }

  public void completeJobOfType(final String jobType, final String jsonVariables) {
    completeJob(jobType, MsgPackUtil.asMsgPackReturnArray(jsonVariables), e -> true);
  }

  public ExecuteCommandResponse completeJob(final long key, final String variables) {
    return completeJob(key, MsgPackUtil.asMsgPackReturnArray(variables));
  }

  public ExecuteCommandResponse completeJob(final long key, final byte[] variables) {
    return apiRule
        .createCmdRequest()
        .type(ValueType.JOB, JobIntent.COMPLETE)
        .key(key)
        .command()
        .put("variables", variables)
        .done()
        .sendAndAwait();
  }

  public void completeJob(
      final String jobType,
      final byte[] variables,
      final Predicate> jobEventFilter) {
    apiRule.activateJobs(partitionId, jobType, 1000L).await();

    final Record jobEvent =
        receiveJobs()
            .withIntent(ACTIVATED)
            .withType(jobType)
            .filter(jobEventFilter)
            .findFirst()
            .orElseThrow(() -> new AssertionError("Expected job locked event but not found."));

    final ExecuteCommandResponse response = completeJob(jobEvent.getKey(), variables);

    assertThat(response.getRecordType()).isEqualTo(RecordType.EVENT);
    assertThat(response.getIntent()).isEqualTo(JobIntent.COMPLETED);
  }

  public ExecuteCommandResponse failJob(final long key, final int retries) {
    return apiRule
        .createCmdRequest()
        .type(ValueType.JOB, JobIntent.FAIL)
        .key(key)
        .command()
        .put("retries", retries)
        .done()
        .sendAndAwait();
  }

  public ExecuteCommandResponse failJobWithMessage(
      final long key, final int retries, final String errorMessage) {
    return apiRule
        .createCmdRequest()
        .type(ValueType.JOB, JobIntent.FAIL)
        .key(key)
        .command()
        .put("retries", retries)
        .put("errorMessage", errorMessage)
        .done()
        .sendAndAwait();
  }

  public ExecuteCommandResponse createJobIncidentWithJobErrorMessage(
      final long key, final String errorMessage) {
    return failJobWithMessage(key, 0, errorMessage);
  }

  public ExecuteCommandResponse updateJobRetries(final long key, final int retries) {
    return apiRule
        .createCmdRequest()
        .type(ValueType.JOB, JobIntent.UPDATE_RETRIES)
        .key(key)
        .command()
        .put("retries", retries)
        .done()
        .sendAndAwait();
  }

  public MessageRecord publishMessage(final Function transformer) {
    return publishMessage(transformer.apply(new MessageRecord()));
  }

  public MessageRecord publishMessage(final MessageRecord request) {
    final ExecuteCommandResponse response =
        executeCommandRequest(ValueType.MESSAGE, MessageIntent.PUBLISH, request);

    assertThat(response.getRecordType()).isEqualTo(RecordType.EVENT);
    assertThat(response.getIntent()).isEqualTo(MessageIntent.PUBLISHED);
    return response.readInto(new MessageRecord());
  }

  public ExecuteCommandResponse publishMessage(
      final String messageName, final String correlationKey) {
    return publishMessage(messageName, correlationKey, new byte[0]);
  }

  public ExecuteCommandResponse publishMessage(
      final String messageName, final String correlationKey, final DirectBuffer variables) {
    return publishMessage(messageName, correlationKey, BufferUtil.bufferAsArray(variables));
  }

  public ExecuteCommandResponse publishMessage(
      final String messageName, final String correlationKey, final String variables) {
    return publishMessage(messageName, correlationKey, MsgPackUtil.asMsgPackReturnArray(variables));
  }

  public ExecuteCommandResponse publishMessage(
      final String messageName,
      final String correlationKey,
      final DirectBuffer variables,
      final long ttl) {
    return publishMessage(messageName, correlationKey, BufferUtil.bufferAsArray(variables), ttl);
  }

  public ExecuteCommandResponse publishMessage(
      final String messageName, final String correlationKey, final byte[] variables) {
    return publishMessage(messageName, correlationKey, variables, Duration.ofHours(1).toMillis());
  }

  public ExecuteCommandResponse publishMessage(
      final String messageName,
      final String correlationKey,
      final byte[] variables,
      final long ttl) {
    return apiRule
        .createCmdRequest()
        .partitionId(partitionId)
        .type(ValueType.MESSAGE, MessageIntent.PUBLISH)
        .command()
        .put("name", messageName)
        .put("correlationKey", correlationKey)
        .put("timeToLive", ttl)
        .put("variables", variables)
        .done()
        .sendAndAwait();
  }

  /////////////////////////////////////////////
  // INCIDENTS //////////////////////////////
  /////////////////////////////////////////////

  public IncidentRecordStream receiveIncidents() {
    return RecordingExporter.incidentRecords().withPartitionId(partitionId);
  }

  public Record receiveFirstIncidentEvent(final IncidentIntent intent) {
    return receiveIncidents().withIntent(intent).getFirst();
  }

  public Record receiveFirstIncidentEvent(
      final long wfInstanceKey, final Intent intent) {
    return receiveIncidents().withIntent(intent).withWorkflowInstanceKey(wfInstanceKey).getFirst();
  }

  public Record receiveFirstIncidentCommand(final IncidentIntent intent) {
    return receiveIncidents().withIntent(intent).onlyCommands().getFirst();
  }

  public ExecuteCommandResponse resolveIncident(final long incidentKey) {

    return apiRule
        .createCmdRequest()
        .partitionId(partitionId)
        .type(ValueType.INCIDENT, IncidentIntent.RESOLVE)
        .key(incidentKey)
        .command()
        .done()
        .sendAndAwait();
  }

  /////////////////////////////////////////////
  // DEPLOYMENTS //////////////////////////////
  /////////////////////////////////////////////

  public DeploymentRecordStream receiveDeployments() {
    return RecordingExporter.deploymentRecords().withPartitionId(partitionId);
  }

  public Record receiveFirstDeploymentEvent(
      final DeploymentIntent intent, final long deploymentKey) {
    return receiveDeployments().withIntent(intent).withRecordKey(deploymentKey).getFirst();
  }

  /////////////////////////////////////////////
  // WORKFLOW INSTANCES ///////////////////////
  /////////////////////////////////////////////

  public WorkflowInstanceRecordStream receiveWorkflowInstances() {
    return RecordingExporter.workflowInstanceRecords().withPartitionId(partitionId);
  }

  public Record receiveFirstWorkflowInstanceCommand(
      final WorkflowInstanceIntent intent) {
    return receiveWorkflowInstances().withIntent(intent).onlyCommands().getFirst();
  }

  public Record receiveFirstWorkflowInstanceEvent(
      final WorkflowInstanceIntent intent) {
    return receiveWorkflowInstances().withIntent(intent).getFirst();
  }

  public Record receiveFirstWorkflowInstanceEvent(
      final WorkflowInstanceIntent intent, final BpmnElementType elementType) {
    return receiveWorkflowInstances().withIntent(intent).withElementType(elementType).getFirst();
  }

  public Record receiveFirstWorkflowInstanceEvent(
      final long wfInstanceKey, final String elementId, final Intent intent) {
    return receiveWorkflowInstances()
        .withIntent(intent)
        .withWorkflowInstanceKey(wfInstanceKey)
        .withElementId(elementId)
        .getFirst();
  }

  public Record receiveFirstWorkflowInstanceEvent(
      final long wfInstanceKey, final Intent intent) {
    return receiveWorkflowInstances()
        .withIntent(intent)
        .withWorkflowInstanceKey(wfInstanceKey)
        .getFirst();
  }

  public Record receiveFirstWorkflowInstanceEvent(
      final long wfInstanceKey, final Intent intent, final BpmnElementType elementType) {
    return receiveWorkflowInstances()
        .withIntent(intent)
        .withWorkflowInstanceKey(wfInstanceKey)
        .withElementType(elementType)
        .getFirst();
  }

  public Record receiveElementInState(
      final String elementId, final WorkflowInstanceIntent intent) {
    return receiveWorkflowInstances().withIntent(intent).withElementId(elementId).getFirst();
  }

  public Record receiveElementInState(
      final long workflowInstanceKey, final String elementId, final WorkflowInstanceIntent intent) {
    return receiveFirstWorkflowInstanceEvent(workflowInstanceKey, elementId, intent);
  }

  public List> receiveElementInstancesInState(
      final Intent intent, final int expectedNumber) {
    return receiveWorkflowInstances()
        .withIntent(intent)
        .limit(expectedNumber)
        .collect(Collectors.toList());
  }

  public List> receiveElementInstancesInState(
      final Intent intent, final BpmnElementType elementType, final int expectedNumber) {
    return receiveWorkflowInstances()
        .withIntent(intent)
        .withElementType(elementType)
        .limit(expectedNumber)
        .collect(Collectors.toList());
  }

  /////////////////////////////////////////////
  // JOBS /////////////////////////////////////
  /////////////////////////////////////////////

  public JobRecordStream receiveJobs() {
    return RecordingExporter.jobRecords().withPartitionId(partitionId);
  }

  public Record receiveFirstJobEvent(final JobIntent intent) {
    return receiveJobs().withIntent(intent).getFirst();
  }

  public Record receiveFirstJobCommand(final JobIntent intent) {
    return receiveJobs().onlyCommands().withIntent(intent).getFirst();
  }

  /////////////////////////////////////////////
  // JOB BATCHS ///////////////////////////////
  /////////////////////////////////////////////

  public JobBatchRecordStream receiveJobBatchs() {
    return RecordingExporter.jobBatchRecords().withPartitionId(partitionId);
  }

  public JobBatchRecordStream receiveFirstJobBatchCommands() {
    return RecordingExporter.jobBatchRecords().withPartitionId(partitionId).onlyCommands();
  }

  /////////////////////////////////////////////
  // MESSAGE //////////////////////////////////
  /////////////////////////////////////////////

  public MessageRecordStream receiveMessages() {
    return RecordingExporter.messageRecords().withPartitionId(partitionId);
  }

  public Record receiveFirstMessageEvent(final MessageIntent intent) {
    return receiveMessages().withIntent(intent).getFirst();
  }

  /////////////////////////////////////////////
  // MESSAGE SUBSCRIPTIONS ////////////////////
  /////////////////////////////////////////////

  public MessageSubscriptionRecordStream receiveMessageSubscriptions() {
    return RecordingExporter.messageSubscriptionRecords().withPartitionId(partitionId);
  }

  /////////////////////////////////////////////
  // MESSAGE SUBSCRIPTIONS ////////////////////
  /////////////////////////////////////////////

  public WorkflowInstanceSubscriptionRecordStream receiveWorkflowInstanceSubscriptions() {
    return RecordingExporter.workflowInstanceSubscriptionRecords().withPartitionId(partitionId);
  }

  /////////////////////////////////////////////
  // TIMER ////////////////////////////////////
  /////////////////////////////////////////////

  public TimerRecordStream receiveTimerRecords() {
    return RecordingExporter.timerRecords().withPartitionId(partitionId);
  }

  public Record receiveTimerRecord(
      final String handlerNodeId, final TimerIntent intent) {
    return receiveTimerRecords().withIntent(intent).withHandlerNodeId(handlerNodeId).getFirst();
  }

  public Record receiveTimerRecord(
      final DirectBuffer handlerNodeId, final TimerIntent intent) {
    return receiveTimerRecord(bufferAsString(handlerNodeId), intent);
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy