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

io.atlassian.aws.swf.SWF.scala Maven / Gradle / Ivy

There is a newer version: 8.0.3
Show newest version
package io.atlassian.aws
package swf

import com.amazonaws.services.simpleworkflow.model._
import kadai.Invalid

import scalaz.std.list._
import scalaz.syntax.all._
import scala.collection.JavaConverters._
import com.amazonaws.services.simpleworkflow.model.{ TaskList => AWSTaskList }

object SWF {
  import SWFAction._

  def register(domain: Domain, config: DomainConfig): SWFAction[Domain] =
    SWFAction.withClient {
      _.registerDomain(
        new RegisterDomainRequest()
          .withName(domain.unwrap)
          .withDescription(config.description)
          .withWorkflowExecutionRetentionPeriodInDays(
            s"${config.retentionPeriod.toDays}"
          )) |> { _ => domain }
    }.handle {
      case Invalid.Err(_: DomainAlreadyExistsException) =>
        // See if the domain is deprecated. If so, then we need to error because the domain is actually not available.
        status(domain).flatMap {
          case RegistrationStatus.DEPRECATED =>
            SWFAction.fail(new DomainDeprecatedException(domain.unwrap))
          case _ =>
            SWFAction.ok(domain)
        }
    }

  private def status(domain: Domain): SWFAction[RegistrationStatus] =
    SWFAction.withClient {
      _.describeDomain(
        new DescribeDomainRequest().withName(domain.unwrap)).getDomainInfo.getStatus |> RegistrationStatus.fromValue
    }

  private def status(domain: Domain, workflow: Workflow): SWFAction[RegistrationStatus] =
    SWFAction.withClient {
      _.describeWorkflowType(
        new DescribeWorkflowTypeRequest().withDomain(domain.unwrap).withWorkflowType(workflow.aws))
        .getTypeInfo.getStatus |> RegistrationStatus.fromValue
    }

  private def status(domain: Domain, activity: Activity): SWFAction[RegistrationStatus] =
    SWFAction.withClient {
      _.describeActivityType(
        new DescribeActivityTypeRequest().withDomain(domain.unwrap).withActivityType(activity.aws))
        .getTypeInfo.getStatus |> RegistrationStatus.fromValue
    }

  def registerWorkflow(workflow: WorkflowDefinition): SWFAction[WorkflowDefinition] =
    for {
      _ <- SWF.register(workflow.domain, workflow.domainConfig)
      _ <- SWF.register(workflow.domain, workflow.workflow, workflow.workflowConfig)
      _ <- workflow.activities[SWFAction].traverseU { a => SWF.register(workflow.domain, a.activity, a.definition) }
    } yield workflow

  def register(domain: Domain, workflow: Workflow, config: WorkflowConfig): SWFAction[Workflow] =
    SWFAction.withClient { w =>
      val req = new RegisterWorkflowTypeRequest().withDescription(config.description).withName(workflow.name)
        .withDefaultExecutionStartToCloseTimeout(config.defaultExecutionStartToCloseTimeout.secAws)
        .withDefaultTaskList(config.defaultTaskList.aws)
        .withDomain(domain.unwrap)
        .withVersion(workflow.version)
        .withDefaultTaskPriority(config.defaultTaskPriority.toString)

      config.defaultTaskStartToCloseTimeout.foreach { d => req.setDefaultTaskStartToCloseTimeout(d.secAws) }
      config.childPolicy.foreach { p => req.setDefaultChildPolicy(p.aws) }

      w.registerWorkflowType(req)
      workflow
    }.handle {
      case Invalid.Err(_: TypeAlreadyExistsException) =>
        // See if the workflow is deprecated. If so, then we need to error because the domain is actually not available.
        status(domain, workflow).flatMap {
          case RegistrationStatus.DEPRECATED =>
            SWFAction.fail(new TypeDeprecatedException(s"Workflow deprecated ${workflow.name}: ${workflow.version}"))
          case _ =>
            SWFAction.ok(workflow)
        }
    }

  def register(domain: Domain, activity: Activity, config: ActivityConfig): SWFAction[Activity] =
    SWFAction.withClient { w =>
      val req = new RegisterActivityTypeRequest().withDescription(config.description).withName(activity.name)
        .withDefaultTaskList(config.defaultTaskList.aws)
        .withDefaultTaskPriority(config.defaultTaskPriority.toString)
        .withDomain(domain.unwrap)
        .withVersion(activity.version)

      config.defaultTaskHeartbeatTimeout.foreach { d => req.setDefaultTaskHeartbeatTimeout(d.secAws) }
      config.defaultTaskScheduleToStart.foreach { d => req.setDefaultTaskScheduleToStartTimeout(d.secAws) }
      config.defaultTaskScheduleToClose.foreach { d => req.setDefaultTaskScheduleToCloseTimeout(d.secAws) }
      config.defaultTaskStartToCloseTimeout.foreach { d => req.setDefaultTaskStartToCloseTimeout(d.secAws) }
      w.registerActivityType(req)
      activity
    }.handle {
      case Invalid.Err(_: TypeAlreadyExistsException) =>
        // See if the activity is deprecated. If so, then we need to error because the domain is actually not available.
        status(domain, activity).flatMap {
          case RegistrationStatus.DEPRECATED =>
            SWFAction.fail(new TypeDeprecatedException(s"Activity deprecated ${activity.name}: ${activity.version}"))
          case _ =>
            SWFAction.ok(activity)
        }
    }

  def poll(query: DecisionQuery): SWFAction[Option[DecisionInstance]] =
    withClient { _.pollForDecisionTask(query.aws) |> DecisionInstance.unapply }

  def poll(query: ActivityQuery): SWFAction[Option[ActivityInstance]] =
    withClient { _.pollForActivityTask(query.aws) |> ActivityInstance.unapply }

  def startWorkflow(domain: Domain, workflow: Workflow, id: WorkflowId, input: String, taskList: Option[TaskList] = None): SWFAction[RunId] = {
    val request: StartWorkflowExecutionRequest =
      new StartWorkflowExecutionRequest().withDomain(domain.unwrap).withWorkflowId(id.unwrap).withWorkflowType(workflow.aws).withInput(input)

    // If taskList is not specified, SWF will use the defaultTaskList defined during workflow registration.
    taskList.foreach(tl => request.withTaskList(new AWSTaskList().withName(tl.unwrap)))

    withClient {
      _.startWorkflowExecution(request).getRunId |> RunId.apply
    }
  }

  def completeDecision(taskToken: TaskToken, context: String, decisions: List[Decision]): SWFAction[Unit] =
    withClient {
      _.respondDecisionTaskCompleted(
        new RespondDecisionTaskCompletedRequest().withTaskToken(taskToken.unwrap).withExecutionContext(context).withDecisions(decisions.map { _.aws }.asJava)
      )
    }

  def heartbeat(taskToken: TaskToken): SWFAction[ActivityTaskStatus] =
    withClient { _.recordActivityTaskHeartbeat(new RecordActivityTaskHeartbeatRequest().withTaskToken(taskToken.unwrap)) }

  def completeActivity(taskToken: TaskToken, result: String): SWFAction[Unit] =
    withClient {
      _.respondActivityTaskCompleted(new RespondActivityTaskCompletedRequest().withTaskToken(taskToken.unwrap).withResult(result))
    }

  def failActivity(taskToken: TaskToken, reason: String, detail: String): SWFAction[Unit] =
    withClient {
      _.respondActivityTaskFailed(new RespondActivityTaskFailedRequest().withTaskToken(taskToken.unwrap).withReason(reason.shortReason).withDetails(detail))
    }

  def cancelActivity(taskToken: TaskToken): SWFAction[Unit] =
    withClient {
      _.respondActivityTaskCanceled(new RespondActivityTaskCanceledRequest().withTaskToken(taskToken.unwrap))
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy