Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NPE terminating both multi-instance body and child elements during PI modification #10537

Closed
remcowesterhoud opened this issue Sep 28, 2022 · 1 comment · Fixed by #10601
Closed
Labels
area/ux Marks an issue as related to improving the user experience hacktoberfest Marks an issue as a candidate to be a Hacktoberfest contribution kind/bug Categorizes an issue or PR as a bug scope/broker Marks an issue or PR to appear in the broker section of the changelog severity/mid Marks a bug as having a noticeable impact but with a known workaround version:8.1.1 Marks an issue as being completely or in parts released in 8.1.1 version:8.2.0-alpha1 Marks an issue as being completely or in parts released in 8.2.0-alpha1 version:8.2.0 Marks an issue as being completely or in parts released in 8.2.0

Comments

@remcowesterhoud
Copy link
Contributor

Describe the bug

Sending a modification request in which we terminate both the multi-instance body as well as any of the elements inside of this multi-instance body will result in a NPE.

image

Terminating the multi-instance body, as well as the subprocess will trigger the NPE.

To Reproduce

Send a terminate request for a multi-instance and any of the element instances within.

Unit test

  @Test
  public void test() {
    // given
    ENGINE
        .deployment()
        .withXmlResource(
            Bpmn.createExecutableProcess(PROCESS_ID)
                .startEvent()
                .subProcess(
                    "A",
                    s ->
                        s.embeddedSubProcess()
                            .startEvent()
                            .userTask("B")
                            .endEvent()
                            .subProcessDone()
                            .multiInstance()
                            .parallel()
                            .zeebeInputCollectionExpression("[1,2,3]")
                            .multiInstanceDone())
                .endEvent()
                .done())
        .deploy();
    final var processInstanceKey = ENGINE.processInstance().ofBpmnProcessId(PROCESS_ID).create();

    final var multiInstanceElement =
        RecordingExporter.processInstanceRecords(ProcessInstanceIntent.ELEMENT_ACTIVATED)
            .withProcessInstanceKey(processInstanceKey)
            .withElementId("A")
            .withElementType(BpmnElementType.MULTI_INSTANCE_BODY)
            .getFirst();
    RecordingExporter.processInstanceRecords(ProcessInstanceIntent.ELEMENT_ACTIVATED)
        .withProcessInstanceKey(processInstanceKey)
        .withElementId("B")
        .withElementType(BpmnElementType.USER_TASK)
        .limit(3)
        .map(Record::getKey)
        .toList();
    final var elements =
        RecordingExporter.processInstanceRecords(ProcessInstanceIntent.ELEMENT_ACTIVATED)
            .withProcessInstanceKey(processInstanceKey)
            .withElementType(BpmnElementType.SUB_PROCESS)
            .limit(3)
            .map(Record::getKey)
            .toList();

    // when
    ENGINE
        .processInstance()
        .withInstanceKey(processInstanceKey)
        .modification()
        .terminateElement(multiInstanceElement.getKey())
        .terminateElement(elements.get(0))
        .terminateElement(elements.get(1))
        .terminateElement(elements.get(2))
        .modify();

    // then
    assertThatElementIsTerminated(processInstanceKey, "A");

    Assertions.assertThat(
            RecordingExporter.processInstanceRecords()
                .onlyEvents()
                .withProcessInstanceKey(processInstanceKey)
                .skipUntil(r -> r.getIntent() == ProcessInstanceIntent.ELEMENT_TERMINATING)
                .limitToProcessInstanceTerminated())
        .extracting(r -> r.getValue().getBpmnElementType(), Record::getIntent)
        .describedAs("Expect that all active instances of the multi-instance have been terminated")
        .containsSequence(
            tuple(BpmnElementType.MULTI_INSTANCE_BODY, ProcessInstanceIntent.ELEMENT_TERMINATING),
            tuple(BpmnElementType.SUB_PROCESS, ProcessInstanceIntent.ELEMENT_TERMINATING),
            tuple(BpmnElementType.USER_TASK, ProcessInstanceIntent.ELEMENT_TERMINATING),
            tuple(BpmnElementType.USER_TASK, ProcessInstanceIntent.ELEMENT_TERMINATED),
            tuple(BpmnElementType.SUB_PROCESS, ProcessInstanceIntent.ELEMENT_TERMINATED),
            tuple(BpmnElementType.SUB_PROCESS, ProcessInstanceIntent.ELEMENT_TERMINATING),
            tuple(BpmnElementType.USER_TASK, ProcessInstanceIntent.ELEMENT_TERMINATING),
            tuple(BpmnElementType.USER_TASK, ProcessInstanceIntent.ELEMENT_TERMINATED),
            tuple(BpmnElementType.SUB_PROCESS, ProcessInstanceIntent.ELEMENT_TERMINATED),
            tuple(BpmnElementType.SUB_PROCESS, ProcessInstanceIntent.ELEMENT_TERMINATING),
            tuple(BpmnElementType.USER_TASK, ProcessInstanceIntent.ELEMENT_TERMINATING),
            tuple(BpmnElementType.USER_TASK, ProcessInstanceIntent.ELEMENT_TERMINATED),
            tuple(BpmnElementType.SUB_PROCESS, ProcessInstanceIntent.ELEMENT_TERMINATED),
            tuple(BpmnElementType.MULTI_INSTANCE_BODY, ProcessInstanceIntent.ELEMENT_TERMINATED),
            tuple(BpmnElementType.PROCESS, ProcessInstanceIntent.ELEMENT_TERMINATING),
            tuple(BpmnElementType.PROCESS, ProcessInstanceIntent.ELEMENT_TERMINATED));
  }

Expected behavior

No NPE should be thrown. If we reach a terminate instruction that doesn't have an existing element instance anymore we should ignore it. We already verified the this instance existed at the start of the command, so it's safe to assume another terminate instruction has already terminated the instance.

Log/Stacktrace

Full Stacktrace

15:24:38.090 [Broker-0-StreamProcessor-1] ERROR io.camunda.zeebe.processor - Expected to process record 'TypedRecordImpl{metadata=RecordMetadata{recordType=COMMAND, intentValue=255, intent=MODIFY, requestStreamId=-2147483648, requestId=-1, protocolVersion=3, valueType=PROCESS_INSTANCE_MODIFICATION, rejectionType=NULL_VAL, rejectionReason=, brokerVersion=8.1.0}, value={"processInstanceKey":2251799813685251,"terminateInstructions":[{"elementInstanceKey":2251799813685255},{"elementInstanceKey":2251799813685256},{"elementInstanceKey":2251799813685257},{"elementInstanceKey":2251799813685258}],"activateInstructions":[]}}' without errors, but exception occurred with message 'Cannot invoke "io.camunda.zeebe.engine.state.instance.ElementInstance.getValue()" because "elementInstance" is null'.
java.lang.NullPointerException: Cannot invoke "io.camunda.zeebe.engine.state.instance.ElementInstance.getValue()" because "elementInstance" is null
	at io.camunda.zeebe.engine.processing.processinstance.ProcessInstanceModificationProcessor.lambda$processRecord$3(ProcessInstanceModificationProcessor.java:201) ~[classes/:?]
	at java.lang.Iterable.forEach(Iterable.java:75) ~[?:?]
	at io.camunda.zeebe.engine.processing.processinstance.ProcessInstanceModificationProcessor.processRecord(ProcessInstanceModificationProcessor.java:197) ~[classes/:?]
	at io.camunda.zeebe.engine.Engine.process(Engine.java:127) ~[classes/:?]
	at io.camunda.zeebe.streamprocessor.ProcessingStateMachine.lambda$processCommand$3(ProcessingStateMachine.java:261) ~[classes/:?]
	at io.camunda.zeebe.db.impl.rocksdb.transaction.ZeebeTransaction.run(ZeebeTransaction.java:84) ~[classes/:?]
	at io.camunda.zeebe.streamprocessor.ProcessingStateMachine.processCommand(ProcessingStateMachine.java:257) ~[classes/:?]
	at io.camunda.zeebe.streamprocessor.ProcessingStateMachine.tryToReadNextRecord(ProcessingStateMachine.java:206) ~[classes/:?]
	at io.camunda.zeebe.streamprocessor.ProcessingStateMachine.readNextRecord(ProcessingStateMachine.java:182) ~[classes/:?]
	at io.camunda.zeebe.scheduler.ActorJob.invoke(ActorJob.java:92) ~[classes/:?]
	at io.camunda.zeebe.scheduler.ActorJob.execute(ActorJob.java:45) ~[classes/:?]
	at io.camunda.zeebe.scheduler.ActorTask.execute(ActorTask.java:119) ~[classes/:?]
	at io.camunda.zeebe.scheduler.ActorThread.executeCurrentTask(ActorThread.java:106) ~[classes/:?]
	at io.camunda.zeebe.scheduler.ActorThread.doWork(ActorThread.java:87) ~[classes/:?]
	at io.camunda.zeebe.scheduler.ActorThread.run(ActorThread.java:198) ~[classes/:?]

Environment:

  • OS:
  • Zeebe Version:
  • Configuration:
@remcowesterhoud remcowesterhoud added the kind/bug Categorizes an issue or PR as a bug label Sep 28, 2022
@remcowesterhoud
Copy link
Contributor Author

@saig0 Please have a look and let me know if you agree here.

@saig0 saig0 added scope/broker Marks an issue or PR to appear in the broker section of the changelog severity/mid Marks a bug as having a noticeable impact but with a known workaround area/ux Marks an issue as related to improving the user experience hacktoberfest Marks an issue as a candidate to be a Hacktoberfest contribution labels Sep 29, 2022
zeebe-bors-camunda bot added a commit that referenced this issue Oct 5, 2022
10608: [Backport stable/8.1] Fix NPE during PI modification r=remcowesterhoud a=backport-action

# Description
Backport of #10601 to `stable/8.1`.

relates to #10537

Co-authored-by: Remco Westerhoud <remco@westerhoud.nl>
zeebe-bors-camunda bot added a commit that referenced this issue Oct 7, 2022
10608: [Backport stable/8.1] Fix NPE during PI modification r=remcowesterhoud a=backport-action

# Description
Backport of #10601 to `stable/8.1`.

relates to #10537

Co-authored-by: Remco Westerhoud <remco@westerhoud.nl>
@korthout korthout added the version:8.1.1 Marks an issue as being completely or in parts released in 8.1.1 label Oct 13, 2022
@korthout korthout added the version:8.2.0-alpha1 Marks an issue as being completely or in parts released in 8.2.0-alpha1 label Nov 1, 2022
@npepinpe npepinpe added the version:8.2.0 Marks an issue as being completely or in parts released in 8.2.0 label Apr 5, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/ux Marks an issue as related to improving the user experience hacktoberfest Marks an issue as a candidate to be a Hacktoberfest contribution kind/bug Categorizes an issue or PR as a bug scope/broker Marks an issue or PR to appear in the broker section of the changelog severity/mid Marks a bug as having a noticeable impact but with a known workaround version:8.1.1 Marks an issue as being completely or in parts released in 8.1.1 version:8.2.0-alpha1 Marks an issue as being completely or in parts released in 8.2.0-alpha1 version:8.2.0 Marks an issue as being completely or in parts released in 8.2.0
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants