SkillAgentSearch skills...

ControlFlow

control-flow library is designed to orchestrate and control the sequence of tasks within Android applications. It harnesses Kotlin coroutines and the Flow API to facilitate smooth task execution and management.

Install / Use

/learn @CodeStarX/ControlFlow
About this skill

Quality Score

0/100

Category

Design

Supported Platforms

Universal

README

<img src="https://i.imgur.com/RKH7Rox.png" >

ControlFlow

ControlFlow is an Android library that facilitates task sequencing, rollback actions, and error handling. It systematically oversees task execution, offering structured error handling and facilitating rollback processes for efficient management.

Explore the implementation of the controlflow library through the code samples available in the ControlFlowDemo. repository.

Features

  • Task Execution Sequencing: Define and manage a sequence of tasks.
  • Subtasks Execution Sequencing: Define and manage a sequence of subtasks for each primary task.
  • Rollback Mechanism: Implement rollback functionalities for tasks that need to revert changes made during their execution.
  • Error Handling: Handle errors occurring during task execution and initiate rollback processes if required.
  • Automated Data Forwarding: Each task's output data type is automatically forwarded as the input for the subsequent task by default.

Installation

To include ControlFlow in your Android project, add the following dependency to your app's build.gradle file:


implementation("io.github.codestarx:control-flow:1.0.0-alpha11")

repositories {
  //..
  //..
  mavenCentral()
}

Task Execution with ControlFlow

  1. Task Management: Create instances of tasks inheriting from Dispatcher and implementing TaskProcessor.
  2. ControlFlow Class: Use the ControlFlow class to manage task sequences and their execution flow.
  3. Start Execution: Begin executing tasks using start() method.

Usage

Task Implementation

Inherit from Dispatcher: Create tasks by inheriting from the Dispatcher class and implementing the TaskProcessor properties. For example:

class MyTask : Dispatcher(), TaskProcessor {
          override val info: TaskInfo
            get() = TaskInfo().apply {
              index = 0
              name = MyTask::class.java.name
              runIn = Dispatchers.IO
            }
        
          override suspend fun doProcess(param: Any?): Flow<TaskStatus> {
            // Define the action here
            return launchAwait(
              action = {
                // Perform the action
                // ...
              },
              transformer = {
                // The output generated by this function will serve as the input for the subsequent task
                // Return TransformData(data= ...)  
              },
              actionCondition = {
                // Define conditions for continuation or breaking
                // Return ConditionData(status = ... , throwable = ... )
              }
            )
          }
}

Handling Rollback

Tasks implementing rollback functionality should also override methods from the RollbackTaskProcessor interface, specifying rollback actions.

Example of a task with rollback:

class MyRollbackTask : Dispatcher(), RollbackTaskProcessor {
          override val info: TaskInfo
            get() = TaskInfo().apply {
              index = 0
              name = MyRollbackTask::class.java.name
              runIn = Dispatchers.IO
            }
        
          override val rollbackInfo: RollbackInfo
            get() = RollbackInfo().apply {
              index = 0
              name = MyRollbackTask::class.java.name
              runIn = Dispatchers.IO
            }
        
          override suspend fun doProcess(param: Any?): Flow<TaskStatus> {
            // Define the action for the task
            return launchAwait(
              action = {
                // Perform the action
                // ...
              },
              actionCondition = {
                // Define conditions for continuation or breaking
                // Return ConditionData(status = ... , throwable = ... )
              }
            )
          }
        
          override suspend fun doRollbackProcess(): Flow<TaskStatus> {
            // Define the rollback action here
            return launchAwait(
              action = {
                // Perform the rollback action
                // ...
              },
              actionCondition = {
                // Define conditions for rollback continuation or breaking
                // Return ConditionData(status = ... , throwable = ... )
              }
            )
          }
} 

Automated Data Forwarding

Each task's output data type is automatically forwarded as the input for the subsequent task by default. If you require altering the output data type passed to the next task, utilize the transformer method for this purpose.

Example:

class Task : Dispatcher(), TaskProcessor {
  override val info: TaskInfo
    get() = TaskInfo().apply {
      index = 0
      name = Task::class.java.name
      runIn = Dispatchers.IO
    }

  override suspend fun doProcess(param: Any?): Flow<TaskStatus> {
    // Define the action here
    return launchAwait(
      action = {
        // Perform the action
        // ...
      },
      transformer = {
        // The output generated by this function will serve as the input for the subsequent task
        // Return TransformData(data= ...)  
      },
      actionCondition = {
        // Define conditions for continuation or breaking
        // Return ConditionData(status = ... , throwable = ... )
      }
    )
  }
}

Attributes Of Each Task

The attributes of each task are outlined using the TaskInfo class. The ‍‍‍‍index, name and runIn parameters define the task's specifications and execution thread. By utilizing index or name and the startFrom method within the ControlFlow, tasks can be rerun as needed.

Example:

class Task : Dispatcher(), TaskProcessor {
  get() = TaskInfo().apply {
    index = 0
    name = Task::class.java.name
    runIn = Dispatchers.IO
  }

  override suspend fun doProcess(param: Any?): Flow<TaskStatus> {
    ...
  }

Activate The Retry Mechanism For Each Task

To activate the Retry mechanism for each task, set the count to define the number of retries in case of failure. Additionally, assign specific causes, a list of errors, to trigger retries upon encountering these errors. Adjust the delay value to determine the interval between each retry attempt.

Example:

class Task : Dispatcher(), TaskProcessor {
  get() = TaskInfo().apply {
    index = 0
    name = Task::class.java.name
    retry = RetryStrategy().apply {
      count = 2
      causes = setOf(TimeoutException::class,AnotherException::class,...)
      delay = 1000L
    }
    runIn = Dispatchers.IO
  }

  override suspend fun doProcess(param: Any?): Flow<TaskStatus> {
    ...
  }

Attributes Of Each Rollback Task

The attributes of each task are outlined using the RollbackInfo class. The ‍‍‍‍index, name and runIn parameters define the task's specifications and execution thread. By utilizing index or name and the startRollbackFrom method within the ControlFlow, tasks can be rerun as needed.

Example:

class Task : Dispatcher(), RollbackTaskProcessor {
  override val info: TaskInfo
    get() = TaskInfo().apply {
      index = 0
      name = Task::class.java.name
      runIn = Dispatchers.IO
    }

  override val rollbackInfo: RollbackInfo
    get() = RollbackInfo().apply {
      index = 0
      name = Task::class.java.name
      runIn = Dispatchers.IO
    }

  override suspend fun doProcess(param: Any?): Flow<TaskStatus> {
    ...
  }

  override suspend fun doRollbackProcess(): Flow<TaskStatus> {
    ...
  }

Activate The Retry Mechanism For Each Rollback Task

To activate the Retry mechanism for each rollback task, set the count to define the number of retries in case of failure. Additionally, assign specific causes, a list of errors, to trigger retries upon encountering these errors. Adjust the delay value to determine the interval between each retry attempt.

Example:

class Task : Dispatcher(), RollbackTaskProcessor {
  override val info: TaskInfo
    get() = ...

  override val rollbackInfo: RollbackInfo
    get() = RollbackInfo().apply {
      index = 0
      name = Task::class.java.name
      retry = RetryStrategy().apply {
        count = 2
        causes = setOf(TimeoutException::class,AnotherException::class,...)
        delay = 1000L
      }
      runIn = Dispatchers.IO
    }

  override suspend fun doProcess(param: Any?): Flow<TaskStatus> {
    ...
  }

  override suspend fun doRollbackProcess(): Flow<TaskStatus> {
    ...
  }

ControlFlow Class

ControlFlow manages the execution sequence of tasks and potential rollback actions. It orchestrates the execution, rollback, completion, and error handling of tasks and their rollbacks. This class offers a structured way to manage a series of tasks and handles their execution flow and potential rollbacks.

Running Control Flow

Example usage:

    // Create a ControlFlow instance
val controlFlow = ControlFlow(object : WorkFlowTracker {
  // Implement work Flow callback methods
})

// Define your tasks
controlFlow.startWith(MyTask())
controlFlow.then(AnotherTask())
controlFlow.then(AnotherTask())

// Set up TaskStatusTracker if needed
controlFlow.useTaskStatusTracker(object : TaskStatusTracker {
  // Implement callback methods
})

// Set up RollbackStatusTracker if needed
controlFlow.useRollbackStatusTracker(object : RollbackStatusTracker {
  // Implement callback methods
})

// Start executing tasks
controlFlow.start()

Subtasks Execution

To incorporate subtasks for each task, you can define their implementation as outlined below:

Example usage:

// Create a ControlFlow instance
val controlFlow = ControlFlow(object : WorkFlowTracker {
  // Implement work Flow callback methods
})

// Define your tasks
controlFlow.startWith(MyTask().apply{
  // Define your subtasks
  then(subtask= MySubtask(
View on GitHub
GitHub Stars15
CategoryDesign
Updated6mo ago
Forks0

Languages

Kotlin

Security Score

72/100

Audited on Sep 8, 2025

No findings