iohao / ioGame

无锁异步化、事件驱动架构设计的 java netty 网络编程框架; 轻量级,无需依赖任何第三方中间件或数据库就能支持集群、分布式; 适用于网络游戏服务器、物联网、内部系统及各种需要长连接的场景; 通过 ioGame 你可以很容易的搭建出一个集群无中心节点、集群自动化、分布式的网络服务器;FXGL、Unity、UE、Cocos Creator、Godot、Netty、Protobuf、webSocket、tcp、socket;java Netty 游戏服务器框架; Java Netty Game Server.
http://game.iohao.com
GNU Affero General Public License v3.0
920 stars 205 forks source link

[内置 kit] 轻量的定时入库辅助功能 #303

Open iohao opened 6 months ago

iohao commented 6 months ago

新增功能的使用场景

在游戏开发中,通常会有定时入库相关需求,其目的是

  1. 为了避免阻塞业务线程,而将入库的操作统一放到其他线程中执行。
  2. 减少 DB 操作(因频繁更新而触发的)。

而定时入库则能很好的解决上述两个点。


现在,框架计划加入定时入库的辅助功能。让我们先看下面这个示例

如下所示,当我们把需要更新的数据放到 FlushData 中时,并不会立即更新,而是会在未来的某个时间点执行更新操作(根据开发者的定时策略)。

FlushData flushData = ...

@Test
public void test() {
    // 添加需要更新的数据 hero、student
    var hero = new Hero();
    hero.id = System.currentTimeMillis();
    flushData.put(hero.id, () -> {
        heroRepository.update(hero);
    });

    var student = new Student();
    student.id = "student-1";
    flushData.put(student.id, () -> {
        studentRepository.update(student);
    });

    // 下面只会更新最后一条数据。因为 id 相同,后者覆盖前者
    var hero2 = new Hero();
    hero2.id = System.currentTimeMillis();

    flushData.put(hero2.id, () -> {
        hero2.name = "first hero2";
        heroRepository.update(hero2);
    });

    flushData.put(hero2.id, () -> {
        hero2.name = "last hero2";
        heroRepository.update(hero2);
    });
}

@Before
public void setUp() {
    BarSkeletonBuilder builder = ...
    // 在游戏逻辑服启动时,我们只需在业务框架中配置相关更新定时策略。
    builder.addRunner(skeleton -> {
        flushData = FlushData.of();
        // 配置 N 分钟同步一次 DB
        TaskKit.runInterval(new FlushIntervalTaskListener(flushData), 5, TimeUnit.MINUTES);
    });
}

FlushData 是框架提供的一个接口,用于管理需要更新的任务

public interface FlushData {
    ... ...省略部分代码
    /**
     * 添加任务监听回调
     *
     * @param id           id
     * @param taskListener 任务监听回调
     */
    void put(long id, TaskListener taskListener);

    /**
     * 添加任务监听回调
     *
     * @param id           id
     * @param taskListener 任务监听回调
     */
    void put(String id, TaskListener taskListener);
}

其他示例代码

class Student {
    String id;
}

class Hero {
    long id;
    String name;
}

interface HeroRepository {
    void update(Hero hero);
}

interface StudentRepository {
    void update(Student student);
}

小结

使用框架提供的定时入库的辅助功能是简单的,只需要两步

  1. 配置定时策略
  2. 将任务添加到 FlushData 中
molin7596 commented 5 months ago

请问一下 TaskKit 与 spring Schedule + Async + Virtual Thread ,TaskKit 优于Schedule 吗, 还是倾向于 提供给非spring使用

iohao commented 5 months ago

请问一下 TaskKit 与 spring Schedule + Async + Virtual Thread ,TaskKit 优于Schedule 吗, 还是倾向于 提供给非spring使用

  1. 提供给非 spring 使用
  2. 学习成本更低,1 分钟之内上手。仅需配置 N 分钟同步一次 DB,及 put 的使用
  3. 扩展性强,定制性强,使用的 TaskListener 接口。

关于 TaskListener 任务监听回调接口,可阅读 TaskKit (yuque.com)

TaskListener 是与时间相关的任务监听回调接口。使用场景有:一次性延时任务、任务调度、轻量可控的延时任务、轻量的定时入库辅助功能 ...等其他扩展场景。


TaskKit 优于 Schedule 吗

两者解决的业务场景不一样,无法比较;除非给出一个特定的业务场景,才能相互比较。

实现方面,TaskKit 与时间相关的统一由 HashedWheelTimer 处理。