docs: @Override
      public void doExecute(final TestContext context) {
          final Message message = createMessage(context, messageType);
          finished = new CompletableFuture<>();
  
          // extract variables from before sending message so we can save dynamic message ids
          for (VariableExtractor variableExtractor : variableExtractors) {
              variableExtractor.extractVariables(message, context);
          }
  
          final Endpoint messageEndpoint = getOrCreateEndpoint(context);
  
          if (StringUtils.hasText(message.getName())) {
              context.getMessageStore().storeMessage(message.getName(), message);
          } else {
              context.getMessageStore().storeMessage(context.getMessageStore().constructMessageName(this, messageEndpoint), message);
          }
  
          if (forkMode) {
              log.debug("Forking message sending action ...");
  
              SimpleAsyncTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor();
              taskExecutor.execute(() -> {
                  try {
                      messageEndpoint.createProducer().send(message, context);
                  } catch (Exception e) {
                      if (e instanceof CitrusRuntimeException) {
                          context.addException((CitrusRuntimeException) e);
                      } else {
                          context.addException(new CitrusRuntimeException(e));
                      }
                  } finally {
                      finished.complete(null);
                  }
              });
          } else {
              try {
                  messageEndpoint.createProducer().send(message, context);
              } finally {
                  finished.complete(null);
              }
          }
      }