code: static TaskInstance createTaskInstance(Long taskId, String masterOwnerId,
              String title, String comment, Instant due, Long userId, Long secondaryOwner)
      throws ServiceException, DataAccessException {
          CodeTimer timer = new CodeTimer("createTaskInstance()", true);
          TaskTemplate task = TaskTemplateCache.getTaskTemplate(taskId);
          TaskInstance ti = createTaskInstance(taskId,  masterOwnerId, OwnerType.USER, userId,
                  (secondaryOwner != null ? OwnerType.DOCUMENT : null), secondaryOwner,
                  task.getTaskName(), title, comment, due, 0);
  
          TaskWorkflowHelper helper = new TaskWorkflowHelper(ti);
  
          if (due!=null) {
              String alertIntervalString = task.getAttribute(TaskAttributeConstant.ALERT_INTERVAL);
              int alertInterval = StringHelper.isEmpty(alertIntervalString) ? 0 : Integer.parseInt(alertIntervalString);
              helper.scheduleTaskSlaEvent(Date.from(due), alertInterval, false);
          }
          // create instance groups for template based tasks
          List<String> groups = helper.determineWorkgroups(null);
          if (groups != null && groups.size() > 0)
              new TaskDataAccess().setTaskInstanceGroups(ti.getTaskInstanceId(), StringHelper.toStringArray(groups));
  
          helper.notifyTaskAction(TaskAction.CREATE, null, null);   // notification/observer/auto-assign
          helper.auditLog("Create", "MDW");
          timer.stopAndLogTiming("");
          return ti;
      }
docs: This version is used by the task manager to create a task instance
  not associated with a process instance.
  
  @param taskId
  @param masterOwnerId
  @param comment optional
  @param due optional
  @param userId
  @param secondaryOwner (optional)
  @return TaskInstance