Open-source project
huahua132/skynet_fly avatar
huahua132/skynet_fly

skynet_fly: a game server framework where services update themselves

基于云风的skynet,搭建开箱即用的微服务框架,提供优雅的服务热更新

532 stars95 forksCMIT

At a glance

What is it?
skynet_fly is a fork of the skynet game server framework in C and Lua, and the feature that defines it is hot update: a module is replaced while the service keeps running, with the old workers drained before the new ones take over. Around that sit an ORM, an HTTP layer with routing and JWT, and a recording system for replaying service behaviour.
Who is it for?
skynet_fly suits a team writing a room based game server or a web backend on the skynet runtime, particularly one that expects to ship code changes to a live service without a maintenance window, since the drain and handover behaviour is the part that is genuinely hard to get right.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 50 days ago.
What is it written in?
Mainly C, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Hot reload is the headline, and the scripts do the work

skynet_fly is a high performance game server framework built on top of skynet, focused on quickly developing web services, game servers and distributed systems that need RPC calls, and it is a fork of the skynet project maintained by the same author rather than a wrapper around the upstream.

The feature list leads with the hot update system, and three items sit under it. It supports updating without stopping the service. It generates the configuration files and the operations scripts in one step. And the mechanism is described as complete, ensuring a smooth transition of the service.

That last point is where the scripts matter. The examples show the whole lifecycle in three commands. You build the service with the make_server script, you run it with the run script, and you apply an update with the check_reload script:

bash
sh ../../binshell/make_server.sh ../../
sh make/script/run.sh load_mods.lua 0

And the reload itself is one command:

bash
sh make/script/check_reload.sh load_mods.lua

The documented behaviour after that is the part worth understanding. The old service exits gracefully once it is confirmed to have no visitors, and the new service takes over the requests without a visible break.

So the update is a handover rather than a restart. The old workers are not killed on the spot; they are drained, and the new ones are brought in behind them. That is what makes the update invisible to connected clients, and it is why the framework needs a way to know when a service has no visitors left, which is a property of the RPC layer rather than of the update script.

The operations scripts generated for a web service make the same point from a different angle. There is a run script to start it, a stop script, a restart script, a reload script for hot updating a module, the check_reload script for detecting and hot updating, and a fasttime script for advancing the clock.

That last one is the most unusual name on the list. Advancing time quickly is a testing aid, and in a game server the passage of time drives everything from cooldowns to daily resets, so being able to skip ahead is the difference between testing a weekly mechanic in an hour and in a week.

The project is MIT licensed, written in C with Lua at the service layer, and the last push was on 2026-09-03, with the release tag following the default branch.

Three calling styles for the same service, and one container client

The first example is the AB_question sample, where a service A sends a message to a service B and receives a reply, and the code for it is the clearest statement of how the RPC layer works.

The A side defines a command function that makes three kinds of call, and the differences between them are the point. A balance_call goes through simple polling load balancing, and the return value and the iteration counter are logged. A mod_call goes through a fixed service mapping, with the module number set explicitly to one before the call. And a broadcast_call sends to all the instances of the service at once.

All three go through the same container_client object, addressed by a service name with an instance suffix, which is the naming convention the framework uses to address a specific instance of a service.

The B side is the trivial half. It defines a hello command that returns a string containing its own address, obtained by asking skynet for the address of the current service. That is the standard way to report which worker answered, and it is what makes the three call styles observable from the log.

The example is deliberately minimal because it isolates the calling convention. Load balancing picks among instances, module mapping pins to one, and broadcast reaches all of them, and the reply tells you which one answered.

The hot update test that follows is the second half of the example. You edit the B service file, run the check_reload script, and the old service exits gracefully once it has no visitors while the new one takes over cleanly.

The second example is a room based game, the digitalbomb sample, and it demonstrates the same idea at a larger scale. It runs over TCP long connections, it supports updating without stopping the service, the login, lobby, matchmaking and game modules are decoupled from each other, and there is a built in test client. The modules listed as hot updatable are hall for the lobby, alloc for allocation, and table for the table itself.

That list is a small architecture in three names. The lobby is where players arrive, allocation hands out a table, and the table runs the game. Splitting them means the game logic can be updated without touching the part that handles connections, which is the whole reason the hot update mechanism is worth building.

The web example shows the routes the framework generates

The third example is a web application, and it is the one that shows the HTTP side of the framework rather than the RPC side.

Building it is the same two steps as the others, and running it has two forms, one in the foreground and one in the background:

bash
sh make/script/run.sh load_mods.lua 0
sh make/script/run.sh load_mods.lua

The service listens on a port and you reach it from a browser, and the example address given is a placeholder IP with port 8688.

The HTTP feature list is short and each item maps to a feature of the framework rather than of the example. HTTP long connection support is there, so a browser can hold a connection open. There is a routing and middleware pattern, which is the part that makes the framework usable as a web backend rather than only as a game server. And JWT authentication is integrated.

The routing and middleware line is the interesting one. A radix router is among the third party dependencies, and a router with a middleware chain is what turns a set of services into something you can put behind a domain name. The JWT piece is built on the luajwtjitsi binding, adapted to work with the lua-openssl binding in the dependency list.

That adaptation note is a small thing that says something about how the project is maintained. The third party table does not only list libraries, it records where they had to be adjusted to fit the rest of the stack, and the JWT entry says explicitly that it has been adapted for lua-openssl.

The web example's hot update flow is the same two steps as the others, first editing the dispatch file and then running the check_reload script. The dispatch file is where the routes live, so changing it is the web equivalent of changing a service, and it demonstrates that the hot update mechanism is not limited to game logic.

Fourteen Lua libraries, and the ones that shape the stack

The third party dependency table is the clearest statement of what the framework expects to exist around it, and it is worth reading as a map of the stack.

The base is skynet itself, a self maintained fork, at the latest version. Then the Lua libraries that get compiled in: basexx at 0.4.1 for base encoding, lua-cjson for JSON parsing, lua-openssl at 0.10.1 for the OpenSSL bindings, lua-protobuf at 0.5.3 for Protobuf support, lua-radix-router for the router, luafilesystem at 1.9.0 for the filesystem, luajwtjitsi at 3.0 for JWT, and lzlib at 0.4.0 for compression.

Then the data structures and tooling that a game server actually leans on: lua-zset for ordered sets, lua-snapshot for the snapshot tool, lua-socket for sockets, LuaPanda as the debugger, and wlua as the Lua tool.

The two that reveal the most about the design are lua-snapshot and LuaPanda. A snapshot library in a server framework is for state capture, and paired with the service record and replay feature it explains how the framework can capture a running service and replay it later. A debugger in the same list, at the level of a first class dependency rather than a development extra, tells you that stepping through a live service is a supported workflow.

The set of supported wire protocols is stated in the game development features: Protobuf, JSON and Sproto are all supported, with a separate dependency for each of the first two. The three are not equivalent. JSON is the readable one that you would use for a configuration file or an admin API, Protobuf is the compact one you would use between services, and Sproto is the lightweight option for the busiest paths.

The data persistence features list the database side of the framework. There is an object relational mapping layer with support for MySQL and MongoDB among others, seamless switching between databases, and a caching strategy for performance, along with wrappers for Redis, MySQL, Timer and Log.

The MySQL and MongoDB pairing with seamless switching is the part that needs care. An ORM that can move between a relational and a document store is either doing something genuinely clever or it is restricting you to the intersection of the two models, and the documentation describes it as supporting multiple databases with switching, so it is worth reading the linked ORM notes before designing a schema around it.

Service record and replay, and the eighteen example directories

The recording and replay feature is the most distinctive item in the feature list and the one with the most detailed documentation of the project.

The list under it names four things. The complete recording of service behaviour. Replay debugging from the recording. Fast location of complex bugs. And automatic hot update records together with shared configuration management.

Recording a running distributed system and replaying it later is a much stronger debugging tool than a log, because a log tells you what happened and a recording lets you ask what would happen. The example set makes this concrete. There is a record directory among the examples, alongside the orm and orm_proxy examples, the log_hook and log_shutdown and logrotate examples, the pre_after_load example, the room_game_jump example, the combat_demo example, and the frpc_client and frpc_server pair.

That list of eighteen example directories is itself informative. Several of the names are about operational behaviour rather than about game features. The logrotate and log_shutdown examples are about keeping logs manageable over a long run, log_hook is about intercepting log output, and pre_after_load is about the lifecycle around loading a module, which is the hook the hot update mechanism uses.

The room_game_jump example is the clearest sign of what this framework is built for. Jumping between rooms mid session is the hardest case in a room based game server, because a client holds state that has to survive the move, and a framework that supports hot updating the game module has to get that right too.

The combat_demo and digitalbomb examples are the game logic side, the digitalbomb_byid and digitalbomb_byrpc variants show the same game addressed two different ways, by identifier and by RPC, which is a comparison of the two addressing styles in the same codebase.

The code_cache_test example is the one that bears directly on the hot update system. If the framework caches code, then a hot update has to invalidate that cache, and an example dedicated to testing that behaviour is what you would expect a project with this much emphasis on live updates to include.

The documentation is published separately from the repository, with a usage guide, an API reference, and detailed pages on the ORM mapping, on the service recording and replay, and on the two hot update articles covering the implementation and the one step build of a service configuration. The homepage points at the usage guide.

Building it, and the submodule that is really the engine

The build is short on Linux. You clone the repository, run the install script for your distribution, and then make linux:

bash
git clone https://github.com/huahua132/skynet_fly
sh install_centos.sh
sh install_ubuntu.sh
make linux

There are two install scripts, one for CentOS and one for Ubuntu, and the choice between them is the platform detection step. The compile step is a single make target, and the Makefile at the top level lists the targets: linux, freebsd and macosx for the three platforms, plus clean, cleanall and upskynet, the last of which updates the skynet repository code.

The Makefile shows why the skynet directory in the repository is a submodule. The skynet build is driven by its own makefile, and the rule that produces the skynet binary depends on a target that runs git submodule update --init and then chmod on the skynet directory. The skynet binary is then built by entering that directory and invoking make with the platform and the TLS module and the TLS include and library paths pointing at the OpenSSL copy in the 3rd directory.

So skynet is fetched at build time rather than vendored, and the submodule update is a build step, not a one-time clone operation. That has a consequence worth knowing, since it means the build needs network access the first time it runs.

The Lua C libraries are then compiled one by one as separate shared objects, and the Makefile shows the pattern for each. The luafilesystem module compiles from its source with the shared library flags and the Lua include path, and the cjson module compiles three source files together, and the protobuf and zlib modules follow the same shape. The list of libraries to build is named in one variable, and it includes lfs, cjson, pb, zlib, chat_filter, openssl, skiplist, snapshot, frpcpack and socket.

Two entries in that list are worth flagging. chat_filter is a C library for filtering chat messages, and frpcpack is for the frpc protocol, which matches the frpc_client and frpc_server examples in the example directory.

The Windows build is described separately, based on Visual Studio 2022, and it needs the CMake module and the Clang module installed. There is a specific note about OpenSSL: if the link fails, download the full MSI installer, and replace the contents of the win3rd include and win3rd lib directories.

That last instruction is a rough edge rather than a defect. The 3rd directory holds vendored copies of the third party sources, and for Windows the OpenSSL copy has to be a real installation rather than the vendored one, because the vendored build does not match what the Windows toolchain expects.

The top level of the repository shows the scope of the thing. There is a skynet directory for the engine, a 3rd directory for the vendored dependencies, an lualib directory for the Lua libraries with an lualib-src directory alongside it, a commonlualib directory, a service directory, a module directory, a script directory, a binshell directory and a binbat directory for the build helpers, an examples directory, a test directory, and a win3rd directory for the Windows third party binaries. There is a CMakeLists.txt and CMakeSettings.json alongside the Makefile, a SECURITY.md and a CODE_OF_CONDUCT.md, and a claude.md file.

Editorial conclusion

skynet_fly suits a team writing a room based game server or a web backend on the skynet runtime, particularly one that expects to ship code changes to a live service without a maintenance window, since the drain and handover behaviour is the part that is genuinely hard to get right. It does not suit you if you want a small dependency, since the framework pulls in fourteen Lua libraries and a vendored OpenSSL, and it does not suit you if you are not comfortable with Lua as the service language. Before you commit, read the ORM notes about switching between a relational and a document store, since that capability is either very useful or a constraint on your schema, and test the hot update path on a service with real clients before you rely on it.

Frequently asked questions

What is skynet_fly and what does it add to skynet?

It is a high performance game server framework built on a self maintained fork of skynet, focused on quickly developing web services, game servers and distributed systems that need RPC calls. Its headline feature is a hot update system that supports updating without stopping the service, with the old service exiting gracefully once it has no visitors.

How do I build skynet_fly on Linux?

Clone the repository, run the install script for your distribution with either sh install_centos.sh or sh install_ubuntu.sh, and then run make linux. The Makefile also lists freebsd and macosx targets, plus clean, cleanall and upskynet for updating the skynet repository code.

What are the three ways to call a service in skynet_fly?

A balance_call uses simple polling load balancing, a mod_call uses a fixed service mapping with the module number set explicitly, and a broadcast_call reaches all instances of the service at once. All three go through the same container client object.

Which database and protocol support does skynet_fly provide?

The persistence layer includes an object relational mapping with support for MySQL and MongoDB among others, seamless switching between databases and a caching strategy, plus wrappers for Redis, MySQL, Timer and Log. The wire protocols supported are Protobuf, JSON and Sproto.

What does the service record and replay feature do?

It records service behaviour completely, replays the recording for debugging, uses that to locate complex bugs quickly, and keeps automatic hot update records with shared configuration management. There is a record example among the example directories and a separate documentation page on the implementation.

Official sources

  1. huahua132/skynet_fly on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/huahua132-skynet-fly.svg)](https://hysenlabs.com/projects/huahua132-skynet-fly)

Was this useful?