ActionGroup

@MainActor
public final class ActionGroup<ContentType> : ActionPerformableCollection where ContentType : ContentTypeable

A group of actions which run concurrently, merging their results into one content value.

The child requests all run concurrently and receive the same input content. When they complete, a ActionResultsMerging object merges their results into a single content value. The group passes this content value and all of the group’s child results via a single ActionResult, and passes the merged value on through its output conduit.

Child failure behavior

Each child’s shouldEndParentTaskOnFailure flag controls what happens when that child fails:

  • true: The group immediately calls cancelAll() on its remaining siblings, builds a group-level ActionResult containing all results collected up to that point plus the failing child’s failure result, and returns cancelled(partialResults:). Siblings that had not yet completed are cancelled.

  • false: The group records the failure and lets all remaining siblings run to completion. Once every child has finished, the group builds a single group-level ActionResult whose origin property includes child results for every task’s success or failure in declaration order, then returns cancelled(partialResults:). The merger is not called because not all children succeeded.

In both cases the caller receives one group ActionResult with a group(results:) origin. Use failedActions() on the partial results to inspect which children failed.

Note

You should not instantiate an ActionGroup directly. Instead you should create an ActionGroupConfiguration object to define it, and used in conjunction with performActions(configuration:content:).

Usage

Build a group by composing child ActionConfiguration objects inside an ActionGroupConfiguration. You can either assign this configuration to interactorsData and run it via its associated event type, or you can build these configurations within a state model and call performActions(configuration:content:) on its Destination.

// Each child configuration represents one parallel Interactor request.
let retrievalChildren: [any ActionConfiguring<InteractorType, ContentType>] = [
    ActionConfiguration<InteractorType, ContentType, MyInteractor>(
        interactorType: .myType,
        action: .retrieveFile,
        assistant: .basicAsync,
        identifier: ActionIdentifier.retrieve),
    ActionConfiguration<InteractorType, ContentType, MyInteractor>(
        interactorType: .myType,
        action: .retrieveFile,
        assistant: .basicAsync,
        identifier: ActionIdentifier.retrieve)
]

// The merger combines each child's result into a single ContentType value.
let retrievals = ActionGroupConfiguration<InteractorType, ContentType>(
    actions: retrievalChildren,
    merger: FileMerger(),
    identifier: ActionIdentifier.retrievalGroup)

let result = await destination.performActions(configuration: retrievals, content: nil)

if case .success(let outputs) = result,
   let groupResult = outputs.last(identifier: ActionIdentifier.retrievalGroup) {
    // groupResult.content holds the merged value from all parallel children.
}
  • id

    A unique identifier for this group instance.

    Declaration

    Swift

    @MainActor
    public let id: UUID
  • The child actions that run concurrently when this group is performed.

    Declaration

    Swift

    @MainActor
    public var actions: [any ActionPerformable<ContentType>]
  • An optional identifier used to tag this group’s ActionResult in the sequence outputs.

    Declaration

    Swift

    @MainActor
    public let identifier: (any ActionIdentifying)?
  • An optional conduit that receives the merged content value and passes it to the next step in the sequence.

    Declaration

    Swift

    @MainActor
    public var outputConduit: (any ActionSequenceConduiting<ContentType>)?
  • Always nil; a group does not represent a single interactor action type.

    Declaration

    Swift

    @MainActor
    public var actionType: (any InteractorRequestActionTypeable)? { get }
  • Controls how a failure in this group propagates to its parent sequence. When true, siblings are cancelled immediately and the group fails fast. When false, all siblings run to completion and every result is collected before the group returns with a .failure Result. See the type-level documentation for the full behavioral description.

    Declaration

    Swift

    @MainActor
    public let shouldEndParentTaskOnFailure: Bool
  • When true, the merged result is recorded in the sequence outputs. Defaults to true.

    Declaration

    Swift

    @MainActor
    public let shouldSaveResult: Bool
  • Determines whether the results of this group’s children are saved in its origin when the group’s result is passed on

    Declaration

    Swift

    @MainActor
    public let shouldSaveChildResults: Bool
  • Creates a new action group.

    Declaration

    Swift

    @MainActor
    public init(actions: [any ActionPerformable<ContentType>]? = nil, merger: any ActionResultsMerging<ContentType>, identifier: (any ActionIdentifying)? = nil, outputConduit: (any ActionSequenceConduiting<ContentType>)? = nil, shouldEndParentTaskOnFailure: Bool? = nil, shouldSaveResult: Bool? = nil, shouldSaveChildResults: Bool? = nil)

    Parameters

    actions

    The child actions to run concurrently. Pass nil to start with an empty group and add actions later via add(action:).

    merger

    The object that merges each child’s ActionResult into a single ContentType value.

    identifier

    An optional identifier attached to the group’s recorded ActionResult.

    outputConduit

    An optional conduit that forwards the merged content value to the next sequence step.

    shouldEndParentTaskOnFailure

    Pass true to cancel sibling actions and fail the sequence when any child fails. Defaults to false.

    shouldSaveResult

    Pass false to skip recording the merged result in the sequence outputs. Defaults to true.

  • Appends an action to the group’s child action list.

    Throws

    ActionError if the action cannot be added.

    Declaration

    Swift

    @MainActor
    public func add(action: any ActionPerformable<ContentType>) throws

    Parameters

    action

    The action to add.

  • Runs all child actions concurrently, merges their results, and returns the updated sequence outputs.

    Each child action receives the same content value and the current sequenceOutputs. When all children complete successfully, their individual ActionResult values are merged into a single ContentType by the group’s ActionResultsMerging object. The group then appends one ActionResult (with origin ActionResponseSource/group(results:)) to the outputs and, if an outputConduit is set, forwards the merged value to the next sequence step.

    Declaration

    Swift

    @MainActor
    public func perform(with content: ContentType?, sequenceOutputs: ActionCollectionResults<ContentType>) async -> Result<ActionCollectionResults<ContentType>, any Error>

    Parameters

    content

    The input content passed to every child action.

    sequenceOutputs

    The accumulated results from all prior steps in the sequence.

    Return Value

    .success with the updated ActionCollectionResults on success, or .failure wrapping an ActionError if a child fails, the merger throws, or the task is cancelled.