Using restinio::run

Simple forms of restinio::run

The simplest way of running RESTinio server is the usage of restinio::run functions. For example, to run single-threaded RESTinio server on the context of the current thread:

restinio::run(
  restinio::on_this_thread()
    .port(8080)
    .address("localhost")
    .request_handler([](auto req) {
      return req->create_response().set_body("Hello, World!").done();
    }));
// The current thread will be blocked until RESTinio server finishes its work.

To run multi-threaded RESTinio server on the context of thread pool:

restinio::run(
  restinio::on_thread_pool(16) // Thread pool size is 16 threads.
    .port(8080)
    .address("localhost")
    .request_handler([](auto req) {
      return req->create_response().set_body("Hello, World!").done();
    }));
// The current thread will be blocked until RESTinio server finishes its work.

Note that run() doesn’t provide a way to stop the server from outside of run(). It means that run() will block the current thread until the server will finish its work by itself. However inside run() a signal handler for SIGINT it installed and the server finishes its work when SIGINT is sent to the application (for example if the user breaks the application by pressing Ctrl+C/Ctrl+Break). Such approach seems to be appropriate for very simple servers like small test programs or quick-and-dirty prototypes. If you need more control you should use restinio::run_async function or restinio::http_server_t class.

A user-defined traits for RESTinio server can be passed as template parameters for restinio::on_this_thread and restinio::on_thread_pool helpers. For example:

using my_traits_t = restinio::traits_t<
    restinio::asio_timer_manager_t,
    restinio::single_threaded_ostream_logger_t,
    restinio::router::express_router_t >;
restinio::run(
  restinio::on_this_thread<my_traits_t>()
    .port(8080)
    .address("localhost")
    .request_handler([](auto req) {
      return req->create_response().set_body("Hello, World!").done();
    }));
// The current thread will be blocked until RESTinio server finishes its work.

Version of restinio::run for an existing http_server_t object

Since v.0.5.1 there is another version of restinio::run function that can be used for an existing http_server_t object. This form can be used in case when an access to http_server_t is necessary from some worker thread. For example:

// Create server instance on the main thread.
using my_server_t = restinio::http_server_t< my_server_traits_t >;
my_server_t server{
   restinio::own_io_context(),
   [](auto & settings) {
      settings.port(...);
      settings.address(...);
      settings.request_handler(...);
      ...
   }
};
// Create a separate thread to control execution of RESTinio's server.
std::thread restinio_control_thread{ [&server] {
      // Use restinio::run to launch RESTinio's server.
      // This run() will return only if server stopped from
      // some other thread.
      restinio::run( restinio::on_thread_pool(
            4, // Count of worker threads for RESTinio.
            restinio::skip_break_signal_handling(), // Don't react to Ctrl+C.
            server) // Server to be run.
         );
   }
};
... // Some application-dependent logic there. Maybe creation of
   // some GUI windows.

// Now RESTinio can be stopped.
restinio::initiate_shutdown(server);
// Wait for completeness of RESTinio's shutdown.
restinio_control_thread.join();

NOTE. There is only restinio::run(restinio::on_thread_pool()) form for running RESTinio with already existing http_server_t instance. If you need some other form of restinio::run please open an issue on GitHub.

run_async function

A helper function restinio::run_async was introduced in v.0.6.7. It allows to run an instance of RESTinio’s server on a separate thread or thread pool. For example:

int main() {
   auto server = restinio::run_async(
      // Asio's io_context to be used.
      // HTTP-server will use own Asio's io_context object.
      restinio::own_io_context(),
      // The settings for the HTTP-server.
      restinio::server_settings_t{}
         .address("127.0.0.1")
         .port(8080)
         .request_handler(...),
      // The size of thread-pool for the HTTP-server.
      16);
   // If we are here and run_async doesn't throw then HTTP-server
   // is started.

   ... // Some other actions.

   // No need to stop HTTP-server manually. It will be automatically
   // stopped in the destructor of `server` object.
}

The run_async returns control when HTTP-server is started or some startup failure is detected. But if a failure is detected then an exception is thrown. So if run_async returns successfuly then HTTP-server is working.

The run_async function returns an instance of restinio::running_service_instance_t<Http_Server> class that can be used for controlling a work of started HTTP-server:

auto server = restinio::run_async(...);

... // Some application specific logic.

// Initiate a shutdown of HTTP-server.
server.stop();

... // Some other application specific actions.

// Wait until HTTP-server finishes its work.
server.wait();

Please note that there is no need to call stop() and wait() methods manually, they will automatically be called by the destructor of running_service_instance_t.

A server to be run asynchronously can be parametrized by custom user-defined traits:

struct my_traits : public restinio::default_traits_t {
   ...
};

auto server = restinio::run_async<my_traits>(
   restinio::own_io_context(),
   restinio::server_settings_t<my_traits>{}
      .address(...)
      .port(...)
      .request_handler(...),
   16u);

NOTE. The function run_async doesn’t install handlers for Ctrl+C/SIGINT signals.

A helper class on_pool_runner_t

Sometimes it is necessary to run http_server_t on a thread pool but without the creation of separate control thread like in the example shown above. In that case a helper class on_pool_runner_t can be used:

// HTTP-server to be run on a thread pool.
restinio::http_server_t< my_traits > server{...};

// Launch HTTP-server on a thread pool.
restinio::on_pool_runner_t< restinio::http_server_t<my_traits> > runner{
      16,
      server
};
runner.start();

... // Some application specific code here.

// Now the server can be stopped.
runner.stop(); // (1)
runner.wait();

NOTE. A manual call to stop() and wait() methods as shown in the point (1) is not necessary: the destructor of on_pool_runner_t will call them automatically if the HTTP-server is not stopped yet.

There are two versions of on_pool_runner_t::start method.

The simplest one is shown above. It doesn’t receive any parameters. It is intended to be used for very simple cases where you don’t care about any errors related to launching of a new server.

There is also a more complicated version of start() method that accepts two callbacks (like http_server_t::open_async()). That method should be used if a user wants to get more controll:

// HTTP-server to be run on a thread pool.
restinio::http_server_t< my_traits > server{...};

// Launch HTTP-server on a thread pool.
restinio::on_pool_runner_t< restinio::http_server_t<my_traits> > runner{
      16,
      server
};

// Use std::promise object for acquiring the result of launching
// a new server.
std::promise<void> run_promise;
runner.start(
   // This callback will be called by RESTinio on successful start.
   [&run_promise]() noexcept {
      // Set a signal about the completion of start procedure.
      run_promise.set_value();
   },
   // This callback will be call by RESTinio in the case of an error.
   [&run_promise](std::exception_ptr ex) noexcept {
      // Store the exception and set a signal of the completion
      // of start procedure.
      run_promise.set_exception(std::move(ex));
   });
// Wait the result of server start.
// NOTE: std::future::get will throw in the case of error, because
// the second callback stored the exception into run_promise.
run_promise.get_future().get();

... // Some application specific code here.

NOTE. Class on_pool_runner_t doesn’t install handlers for Ctrl+C/SIGINT signals.