Dynamically Adjusting Server Configuration¶
iFun Engine provides RESTful API to dynamically change some of the server configuration. Mutable configuration includes iFun Engine flags as shown below and your own flags. (Since iFun Engine relies on Google Gflags for its command-line flag processing, you can easily add your own flags. Please refer to the Google Gflags documents for details.)
minloglevel
: This changes the minimum log level.v
: This changes the verbosity.alsologtostderr
: This turns on/off log messages to the standard error in addition to the log file.session_message_logging_level
: This changes log levels for session messages between the client and the server. 0 for no session message logging, 1 for message type and length only, and 2 for entire message dump. Please refer to Networking parameters for details.rpc_message_logging_level
: This changes log levels for RPC messages between servers. 0 for no message logging, 1 for message type and length only, and 2 for entire message dump. Please see Distribution parameters for details.enable_event_profiler
: This turns on/off the iFun Engine’s event profiling feature. Please refer to Event profiling: details for details.event_threads_size
: This changes the number of main threads. Please refer to Event parameters.client_current_version
: This changes the required client version to connect the server. This can prevent clients with invalid versions from connecting to the server. Please refer to Client version control.
Important
Please be aware that the change is tentative and does not mean overwriting the MANIFEST.json
file.
Configuring MANIFEST.json¶
To enable dynamic configuration changes, a component named RuntimeConfiguration
should be listed in the MANIFEST.json
file.
Note
If you have created a project with iFun Engine version 1.0.0-1401 or later, the component is already in the generated MANIFEST.json and you do not have to include it manually.
Important
RuntimeConfiguration
relies on the ApiService
component.
So, please make sure you enabled the ApiService
component referring to ApiService parameters.
"RuntimeConfiguration": {
"enable_runtime_configuration": true,
"additional_configurations": []
}
enable_runtime_configuration
: This should be set to true to enable the feature.additional_configurations
: You can specify a list of custom gflags to allow dynamic re-configuration. (E.g., [“myflag1”, “myflag2”])Tip
You cannot add iFun Engine’s flags in the list. But it is allowed to include flags related to
Glog
orGflag
.
RESTful APIs¶
To retrieve all the current flag values¶
-
GET
/v1/configurations/
¶ Request example:
GET /v1/configurations/ HTTP/1.1
Response example:
HTTP/1.1 200 OK Content-Type: application/json { "minloglevel": { "type": "int32", "desc": "Messages logged at a lower level than this don't actually get logged anywhere", "value": "0" }, ... }
To read a specific flag¶
-
GET
/v1/configurations/
(flag_name)¶ - Parameters
flag_name – the name of a flag in question.
Example - in case that the flag name indeed exists:
Request
GET /v1/configurations/minloglevel HTTP/1.1
Response
HTTP/1.1 200 OK Content-Type: application/json { "minloglevel": { "type": "int32", "desc": "Messages logged at a lower level than this don't actually get logged anywhere", "value": "0" } }
Example - in case that the flag name does not exist.:
Request
GET /v1/configurations/no_flag HTTP/1.1
Response
HTTP/1.1 400 Bad Request Content-Type: application/json { "no_flag": { "message": "This is not available", "available_configurations": { "minloglevel": { "type": "int32", "desc": "Messages logged at a lower level than this don't actually get logged anywhere" }, ... } } }
To change a specific flag¶
-
PUT
/v1/configurations/
(flag_name)/
(value)¶ - Parameters
flag_name – the name of a flag to update
value – new value
Example - in case the the value is legitimate:
Request
PUT /v1/configurations/minloglevel/1 HTTP/1.1
Reply
HTTP/1.1 200 OK Content-Type: application/json { "minloglevel": { "result": "minloglevel set to 1\n" } }
Example - in case the value is not legitimate:
Request
PUT /v1/configurations/minloglevel/one HTTP/1.1
Reply
HTTP/1.1 400 Bad Request Content-Type: application/json { "minloglevel": { "result": "The 'one' is not a valid value" } }
To read and update the information on compatible client versions¶
You can retrieve the compatible client version information specified by the client_compatible_versions
of the AppInfo
component in MANIFEST.json
in this way:
-
GET
/v1/configurations/compatible_client_versions
¶ Example:
Request
GET /v1/configurations/compatible_client_versions HTTP/1.1
Reply:
HTTP/1.1 200 OK Content-Type: application/json { "current_compatible_versions": ["0.0.1","0.0.2"] }
Also, you can override the compatible client version information like this:
-
POST
/v1/configurations/compatible_client_versions
¶ Example
Request:
POST /v1/configurations/compatible_client_versions HTTP/1.1 ["0.0.3", "0.0.4"]
Reply:
HTTP/1.1 200 OK Content-Type: application/json { "current_compatible_versions": ["0.0.3", "0.0.4"] }
Important
Again, the change is tentative and will be reset once the server reboots. This means the update query does not overwrite the MANIFEST.json file.
Make custom flags dynamically configurable¶
Say, we defined a command-line flag using the Google Gflags.
DEFINE_bool(enable_gold_event, // names the flag.
false, // gives the default value for the flag.
"gold event flag"); // gives a long description about the flag.
If we want to make the enable_gold_event
flag dynamically mutable, we need to add it to the additional_configuration
field of the RuntimeConfiguration
component.
"RuntimeConfiguration": {
"enable_runtime_configuration": true,
"additional_configurations": ["enable_gold_event"]
}
OK. The flag is ready to be updated now. We then need to figure out how to update.
Pitfall: reflecting flag value changes to real changes¶
Say, we want to update the enable_gold_event
flag explained in Make custom flags dynamically configurable.
Let’s make the scenario more realistic. Say, the flag defaults to false and is used in a code like this way:
// user.cc
DEFINE_bool(enable_gold_event, false, "gold event flag");
void OnLogin() {
Ptr<User> user = User::Fetch(...);
// If enable_gold_event flag is turned on, the player gets extra 100 gold on log in.
if (FLAGS_enable_gold_event) {
user->SetGold(user->GetGold() + 100);
}
}
We may want to turn on the flag for a while to attract more players.
Request
PUT /v1/configurations/enable_gold_event/true
Tip
Any non-zero values are treated as true.
Reply
HTTP/1.1 200 OK
Content-Type: application/json
{
"enable_gold_event": {
"result": "enable_gold_event set to true\n"
}
}
You might write a code snippet that copies the Google flag value to a variable, rather than directly reading the flag. But, please keep it mind that this approach will not work, since changes to the flag do not imply changes to the variable. For example, say we have a class named EventManager
which keeps track of in-game campaigns and the class has a method named EventManager::IsGoldEventEnabled
that returns a internal copy of the Google flag. Code would look like this:
// server.cc
DEFINE_bool(enable_gold_event, false, "gold event flag");
// Assume below method is invoked when the server starts.
void Start() {
// the enable_gold_event flag is set to false, by default.
// We are passing the flag value when initialization our EventManager class.
EventManager::Initialize(FLAGS_enable_gold_event);
}
// event_manager.cc
bool the_is_gold_event_enabled = false;
void EventManager::Initialize(bool is_gold_event_enabled) {
// The initialization method makes a local copy of the flag.
the_is_gold_event_enabled = is_gold_event_enabled;
}
bool EventManager::IsGoldEventEnabled() {
// This getter method simply returns the local copy.
return the_is_gold_event_enabled;
}
// user.cc
void OnLogin() {
Ptr<User> user = User::Fetch(...);
// We will reward the user some gold if the gold campaign is in progress.
// But this code has a flaw, since EventManager::IsGoldEventEnabled() cached the flag value.
if (EventManager::IsGoldEventEnabled()) {
user->SetGold(user->GetGold() + 100);
}
}
As we outlined above, EventManager::Initialize()
returns a local copy of the enable_gold_event
Google flag.
So, changes to the flag are not relevant to the local variable. And this is obviously not what we want. So, please do not forget to directly read the flag if the flag is set to mutable via the REST API. Correct code should look like this:
// server.cc
DEFINE_bool(enable_gold_event, false, "gold event flag");
// Assume below method is invoked when the server starts.
void Start() {
// Please note that we are not passing the flag value anymore.
EventManager::Initialize();
}
// event_manager.cc
// To read the flag, we need to use Google flags DECLARE_*(...) macros.
// In this example, we will use DECLARE_bool(...) as the flag is boolean.
DECLARE_bool(enable_gold_event);
void EventManager::Initialize() {
...
}
bool EventManager::IsGoldEventEnabled() {
// This function now reads the flag directly, which is correct.
return FLAGS_enable_gold_event;
}
// user.cc
void OnLogin() {
Ptr<User> user = User::Fetch(...);
// Now, we can turn on/off the event via the REST API.
if (EventManager::IsGoldEventEnabled()) {
user->SetGold(user->GetGold() + 100);
}
}