Skip to content

Conversation

@Fabilin
Copy link
Member

@Fabilin Fabilin commented Aug 13, 2025

resolves #1907 by adding classes and utilities for executing stories on coroutines.

Note

All new elements are annotated with a new @ExperimentalTockCoroutines opt-in annotation, to avoid reliance while the API is still unstable.

New StoryDefinition hierarchy

classDiagram
    class StoryDefinition {
        <<interface>>
        +StoryHandler storyHandler
        +Set[StoryStep] steps
    }
    class AsyncStoryDefinition {
        <<interface>>
        +AsyncStoryHandler storyHandler
        +Set[AsyncStoryStep] steps
    }
    class StoryHandler {
        <<interface>>
    }
    class AsyncStoryHandler {
        <<interface>>
    }
    class AsyncStoryHandlerBase {
        <<abstract>>
    }
    class AsyncDelegatingStoryHandlerBase {
        <<abstract>>
    }
    class AsyncConfigurableStoryHandler
    class StoryStepDef {
        <<interface>>
    }
    class StoryStep {
        <<interface>>
    }
    class AsyncStoryStep {
        <<interface>>
    }
    class AsyncStoryHandling {
        <<interface>>
    }
    class AsyncStoryHandlingBase {
        +AsyncConnectorHandling connector
    }
    class AsyncConnectorHandling {
        <<interface>>
    }
    class AsyncConnectorHandlingBase

    StoryDefinition <|.. AsyncStoryDefinition
    StoryDefinition o-- StoryHandler
    StoryDefinition o-- StoryStepDef
    AsyncStoryDefinition o-- AsyncStoryHandler
    AsyncStoryDefinition o-- AsyncStoryStep
    AsyncStoryHandler <|.. StoryHandler
    AsyncStoryHandlerBase ..|> AsyncStoryHandler
    AsyncDelegatingStoryHandlerBase ..|> AsyncStoryHandlerBase
    AsyncConfigurableStoryHandler --|> AsyncDelegatingStoryHandlerBase
    StoryStep <|.. StoryStepDef
    AsyncStoryStep <|.. StoryStepDef
    AsyncStoryHandlingBase ..|> AsyncStoryHandling
    AsyncStoryHandlingBase o-- AsyncConnectorHandling
    AsyncConnectorHandlingBase ..|> AsyncConnectorHandling
Loading

New classes:

  • AsyncStoryDefinition: StoryDefinition specialized for AsyncStoryHandler and AsyncStoryStep
  • AsyncStoryHandler: subtype of StoryHandler with a suspending handle method. It has special casing in Story.handle.
    • AsyncStoryHandlerBase: the most basic implementation of AsyncStoryHandler. The functionality present in StoryHandlerBase is split between this class and AsyncDelegatingStoryHandlerBase.
    • AsyncDelegatingStoryHandlerBase: a specialization of AsyncStoryHandlerBase which handles preconditions, steps, and custom AsyncStoryHandling
  • AsyncStoryHandling: equivalent to StoryHandlerDefinition. The naming scheme is changed to be shorter and somewhat more meaningful. Unlike the former, this interface does not directly extend AsyncBus nor require a connector instance, letting implementations decide if they want the utilities.
    • AsyncStoryHandlingBase: equivalent to StoryHandlerDefinitionBase. Also implements AsyncBus for convenient access to its methods.
  • AsyncConnectorHandling: equivalent to ConnectorStoryHandler. The naming scheme is changed to be shorter and somewhat more meaningful. Unlike the former, this interface does not directly extend AsyncBus, letting implementations decide if they want the utilities.
    • AsyncConnectorHandlingBase: equivalent to ConnectorStoryHandlerBase. Tightly coupled to AsyncStoryHandlingBase, for type safety.

Utilities

  • Executor.launchCoroutine: a new method to launch a coroutine from a TOCK Executor

Design Decisions

AsyncBus limits access to BotBus-specific data like UserTimeline. The goal is to eventually have an AsyncClientBus implementation for TOCK Bot API mode. Ideally, AsyncStoryStep and AsyncStoryHandling could also be used in a Bot API client.

Backward Compatibility

Source incompatibilities

  • StoryStep has a new supertype, which is notably used by StoryDefinition. Some advanced code may need to update their typing when iterating through a story's steps.

Binary incompatibilities

  • All connector message factory methods now take a StoryStepDef instead of a StoryStep<out StoryHandlerDefinition.
    This should not cause any source incompatibility.

Other

  • The ConnectorHandler annotation now allows any ConnectorSpecificHandling, not just ConnectorStoryHandler. Third-party connector implementations should update their typing to allow use with async story handlers.
  • This PR has the side-effect of making TockConnectorController#handleAction always run asynchronously in a Vert.x worker thread, whereas it previously ran on the calling thread unless the usertimeline was locked. This change is likely to reduce contention on event loop threads, which would be an improvement, but it may have other unintended effects.
  • TockBotBus attempts to preserve coroutine scopes when switching between regular and async stories. This may cause thread starvations if too many story switches happen at once.

@Fabilin Fabilin requested a review from vsct-jburet August 13, 2025 16:21
@Fabilin Fabilin marked this pull request as ready for review August 18, 2025 07:48
@Fabilin Fabilin marked this pull request as draft August 28, 2025 14:51
@Fabilin Fabilin force-pushed the 1907-story-coroutines branch from 1d75dbc to dd180b6 Compare September 1, 2025 12:39
@Fabilin Fabilin marked this pull request as ready for review September 1, 2025 12:39
Copy link
Member Author

@Fabilin Fabilin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some comments after review by @vsct-jburet

@vsct-jburet vsct-jburet added this to the 25.9.0 milestone Sep 24, 2025
@vsct-jburet vsct-jburet merged commit 9e7c6c9 into theopenconversationkit:master Sep 24, 2025
2 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bot Engine] allow asynchronous operations in story handlers

2 participants