Skip to main content

FlowContext

Introduction

FlowContext is the context for action flow processing in the business framework. Its lifecycle exists only for the current action request. If you have only used web development before, you can temporarily think of it like a request-scoped context (similar in spirit to Cookie usage patterns).

FlowContext capabilities include but are not limited to:

  • Accessing userId.
  • Dynamic attributes.
  • Communication capabilities with convenient sync, async, async-callback APIs for communication models, and supports full-link call log tracing.
  • Supports extension of meta information - attachments (developers can extend user-data storage).
  • Supports custom extension (developers can tailor APIs suitable for team/business).
  • Access to the current FlowContext thread executor, enabling lock-free high concurrency patterns.

Because FlowContext includes communication capabilities and provides convenient sync, async, async-callback APIs plus full-link tracing, you can write concise cross-server calls or send data to yourself.

Business Framework Flowchart

The figure below shows the action processing flow. FlowContext passes through each stage in the diagram.

An

How to Get FlowContext

You only need to define this parameter in action method parameters. The framework recognizes it automatically.

@ActionController(1)
public class DemoAction {
@ActionMethod(1)
public void demo(FlowContext flowContext) {
}
}

userId

After user login, userId can be obtained through flowContext.

long userId = flowContext.getUserId();

Custom FlowContext

The framework supports extending FlowContext. If existing capabilities do not meet your business needs, you can enhance it through extension. This section defines a custom FlowContext and adds custom methods.

@Setter
public class MyFlowContext extends DefaultFlowContext {
public String getNickname() {
return "Michael Jackson";
}
}

Set custom FlowContext

static void main() {
CoreGlobalConfig.setting.flowContextFactory = MyFlowContext::new;
}

Usage in action

Custom MyFlowContext is used in the same way as framework default FlowContext.

@ActionController(MyCmd.cmd)
public class MyAction {
@ActionMethod(MyCmd.nickname)
private String getNickname(MyFlowContext flowContext) {
return flowContext.getNickname();
}
}

Thread Executors - Lock-Free High Concurrency

FlowContext provides access to user-associated executors, including user virtual-thread executor and user-thread executor. The framework provides an elegant thread-executor design, making lock-free high-concurrency code easier to implement.

See thread-related section for details.


UserThreadExecutorRegion is the user-thread executor and also the executor that consumes action business logic. Developers can submit tasks to this executor to avoid concurrency issues.

  • code 2: execute task with user thread; method includes full-link tracing.
  • code 6: submit task to user thread executor.
void executor() {
flowContext.execute(() -> {
// your code
});

flowContext.getExecutor().execute(() -> {
// your code
});
}

UserVirtualThreadExecutorRegion is the user virtual-thread executor. Developers can submit IO/blocking tasks to this executor.

  • code 2: execute task with virtual thread; method includes full-link tracing.
  • code 6: submit task to virtual-thread executor.
void executeVirtual() {
flowContext.executeVirtual(() -> {
// your code
});

flowContext.getVirtualExecutor().execute(() -> {
// your code
});
}

Communication Capabilities

FlowContext integrates communication model and provides convenient sync, async, async-callback APIs. For more examples, see Examples Communication.

Besides broadcast APIs, it also supports broadcasting to self via APIs prefixed with broadcastMe.

@ActionController(FlowContextBroadcastCmd.cmd)
public class FlowContextBroadcastAction {
AtomicInteger inc = new AtomicInteger();

@ActionMethod(triggerBroadcastMe)
private void triggerBroadcastMe(FlowContext flowContext) {
// ---------- empty ----------
flowContext.broadcastMe(broadcastMeEmpty);

// ---------- int ----------
int dataInt = inc.getAndIncrement();
flowContext.broadcastMe(broadcastMeInt, dataInt);

// ---------- boolean ----------
boolean dataBool = inc.getAndIncrement() % 2 == 0;
flowContext.broadcastMe(broadcastMeBool, dataBool);

// ---------- long ----------
long dataLong = inc.getAndIncrement();
flowContext.broadcastMe(broadcastMeLong, dataLong);

// ---------- string ----------
String dataString = "ionet-" + inc.getAndIncrement();
flowContext.broadcastMe(broadcastMeString, dataString);

// ---------- object ----------
BookMessage dataObject = new BookMessage();
dataObject.authorName = "ionet";
dataObject.bookName = "book-" + inc.getAndIncrement();
flowContext.broadcastMe(broadcastMeObject, dataObject);

// ---------- list int ----------
List<Integer> dataListInt = List.of(inc.getAndIncrement(), inc.getAndIncrement());
flowContext.broadcastMeListInt(broadcastMeIntList, dataListInt);

// ---------- list boolean ----------
List<Boolean> dataListBool = List.of(
inc.getAndIncrement() % 2 == 0,
inc.getAndIncrement() % 2 == 0
);

flowContext.broadcastMeListBool(broadcastMeBoolList, dataListBool);

// ---------- list long ----------
List<Long> dataListLong = List.of(
(long) inc.getAndIncrement(),
(long) inc.getAndIncrement()
);

flowContext.broadcastMeListLong(broadcastMeLongList, dataListLong);

// ---------- list string ----------
List<String> dataListString = List.of(
"ionet-" + inc.getAndIncrement(),
"ionet-" + inc.getAndIncrement()
);

flowContext.broadcastMeListString(broadcastMeStringList, dataListString);

// ---------- list object ----------
BookMessage message1 = new BookMessage();
message1.authorName = "ionet";
message1.bookName = "book-" + inc.getAndIncrement();

BookMessage message2 = new BookMessage();
message2.authorName = "ionet";
message2.bookName = "book-" + inc.getAndIncrement();

List<BookMessage> dataList = List.of(message1, message2);
flowContext.broadcastMe(broadcastMeObjectList, dataList);
}
}

Summary

FlowContext is the request context of current action. Through FlowContext, you can access almost all information of current logic server and business framework. If existing capabilities are not enough, you can extend FlowContext.

FlowContext integrates common APIs:

  • Communication-related:
    • Convenient sync, async, async-callback for internal requests.
    • Broadcast.
    • EventBus.
    • OnExternal.
  • Meta info-related:
    • updateAttachment synchronous update.
    • updateAttachmentAsync asynchronous update.
  • Thread-executor-related:
    • User virtual-thread executor.
    • User thread executor.