RESTinio
Loading...
Searching...
No Matches
http_server_run.hpp
Go to the documentation of this file.
1/*
2 * restinio
3 */
4
5/*!
6 * \file
7 * \brief Helper function for simple run of HTTP server.
8 */
9
10#pragma once
11
12#include <restinio/impl/ioctx_on_thread_pool.hpp>
13
14#include <restinio/http_server.hpp>
15
16namespace restinio
17{
18
19//
20// break_signal_handling_t
21//
22/*!
23 * @brief Indication of usage of break signal handlers for some forms
24 * of run functions.
25 *
26 * @since v.0.5.1
27 */
29{
30 //! Signal handler should be used by run() function.
32 //! Signal handler should not be used by run() function.
34};
35
36/*!
37 * @brief Make the indicator for usage of break signal handler.
38 *
39 * Usage example:
40 * @code
41 * restinio::run( restinio::on_thread_pool(
42 * std::thread::hardware_concurrency(),
43 * restinio::use_break_signal_handling(),
44 * my_server) );
45 * @endcode
46 *
47 * @since v.0.5.1
48 */
49inline constexpr break_signal_handling_t
54
55/*!
56 * @brief Make the indicator for absence of break signal handler.
57 *
58 * Usage example:
59 * @code
60 * restinio::run( restinio::on_thread_pool(
61 * std::thread::hardware_concurrency(),
62 * restinio::skip_break_signal_handling(),
63 * my_server) );
64 * @endcode
65 *
66 * @since v.0.5.1
67 */
68inline constexpr break_signal_handling_t
73
74//
75// run_on_this_thread_settings_t
76//
77/*!
78 * \brief Settings for the case when http_server must be run
79 * on the context of the current thread.
80 *
81 * \note
82 * Shouldn't be used directly. Only as result of on_this_thread()
83 * function as parameter for run().
84 */
85template<typename Traits>
86class run_on_this_thread_settings_t final
88 run_on_this_thread_settings_t<Traits>,
89 Traits>
90{
92 run_on_this_thread_settings_t<Traits>, Traits>;
93public:
94 // Inherit constructors from base class.
96};
97
98//
99// on_this_thread
100//
101/*!
102 * \brief A special marker for the case when http_server must be
103 * run on the context of the current thread.
104 *
105 * Usage example:
106 * \code
107 * // Run with the default traits.
108 * run( restinio::on_this_thread()
109 * .port(8080)
110 * .address("localhost")
111 * .request_handler(...) );
112 * \endcode
113 * For a case when some custom traits must be used:
114 * \code
115 * run( restinio::on_this_thread<my_server_traits_t>()
116 * .port(8080)
117 * .address("localhost")
118 * .request_handler(...) );
119 * \endcode
120 */
121template<typename Traits = default_single_thread_traits_t>
122run_on_this_thread_settings_t<Traits>
123on_this_thread() { return run_on_this_thread_settings_t<Traits>{}; }
124
125//
126// run_on_thread_pool_settings_t
127//
128/*!
129 * \brief Settings for the case when http_server must be run
130 * on the context of the current thread.
131 *
132 * \note
133 * Shouldn't be used directly. Only as result of on_thread_pool()
134 * function as parameter for run().
135 */
136template<typename Traits>
137class run_on_thread_pool_settings_t final
139 run_on_thread_pool_settings_t<Traits>,
140 Traits>
141{
142 //! Size of the pool.
143 std::size_t m_pool_size;
144
145public:
146 //! Constructor.
148 //! Size of the pool.
149 std::size_t pool_size )
150 : m_pool_size(pool_size)
151 {}
152
153 //! Get the pool size.
154 std::size_t
155 pool_size() const { return m_pool_size; }
156};
157
158//
159// on_thread_pool
160//
161/*!
162 * \brief A special marker for the case when http_server must be
163 * run on an thread pool.
164 *
165 * Usage example:
166 * \code
167 * // Run with the default traits.
168 * run( restinio::on_thread_pool(16) // 16 -- is the pool size.
169 * .port(8080)
170 * .address("localhost")
171 * .request_handler(...) );
172 * \endcode
173 * For a case when some custom traits must be used:
174 * \code
175 * run( restinio::on_thread_pool<my_server_traits_t>(16)
176 * .port(8080)
177 * .address("localhost")
178 * .request_handler(...) );
179 * \endcode
180 */
181template<typename Traits = default_traits_t>
182run_on_thread_pool_settings_t<Traits>
184 //! Size of the pool.
185 std::size_t pool_size )
186{
187 return run_on_thread_pool_settings_t<Traits>( pool_size );
188}
189
190//
191// run()
192//
193
194
195//! Helper function for running http server until ctrl+c is hit.
196/*!
197 * Can be useful when RESTinio server should be run on the user's
198 * own io_context instance.
199 *
200 * For example:
201 * \code
202 * asio::io_context iosvc;
203 * ... // iosvc used by user.
204 * restinio::run(iosvc,
205 * restinio::on_this_thread<my_traits>()
206 * .port(8080)
207 * .address("localhost")
208 * .request_handler([](auto req) {...}));
209 * \endcode
210 *
211 * \since
212 * v.0.4.2
213 */
214template<typename Traits>
215inline void
217 //! Asio's io_context to be used.
218 //! Note: this reference should remain valid until RESTinio server finished.
219 asio_ns::io_context & ioctx,
220 //! Settings for that server instance.
221 run_on_this_thread_settings_t<Traits> && settings )
222{
223 using settings_t = run_on_this_thread_settings_t<Traits>;
224 using server_t = http_server_t<Traits>;
225
226 server_t server{
228 std::forward<settings_t>(settings) };
229
230 std::exception_ptr exception_caught;
231
232 asio_ns::signal_set break_signals{ server.io_context(), SIGINT };
233 break_signals.async_wait(
234 [&]( const asio_ns::error_code & ec, int ){
235 if( !ec )
236 {
237 server.close_async(
238 [&]{
239 // Stop running io_service.
240 ioctx.stop();
241 },
242 [&exception_caught]( std::exception_ptr ex ){
243 // We can't throw an exception here!
244 // Store it to rethrow later.
245 exception_caught = ex;
246 } );
247 }
248 } );
249
250 server.open_async(
251 []{ /* Ok. */},
252 [&ioctx, &exception_caught]( std::exception_ptr ex ){
253 // Stop running io_service.
254 // We can't throw an exception here!
255 // Store it to rethrow later.
256 ioctx.stop();
257 exception_caught = ex;
258 } );
259
260 ioctx.run();
261
262 // If an error was detected it should be propagated.
263 if( exception_caught )
264 std::rethrow_exception( exception_caught );
265}
266
267//! Helper function for running http server until ctrl+c is hit.
268/*!
269 * This function creates its own instance of Asio's io_context and
270 * uses it exclusively.
271 *
272 * Usage example:
273 * \code
274 * restinio::run(
275 * restinio::on_this_thread<my_traits>()
276 * .port(8080)
277 * .address("localhost")
278 * .request_handler([](auto req) {...}));
279 * \endcode
280 */
281template<typename Traits>
282inline void
284 run_on_this_thread_settings_t<Traits> && settings )
285{
286 asio_ns::io_context io_context;
287 run( io_context, std::move(settings) );
288}
289
290namespace impl {
291
292/*!
293 * \brief An implementation of run-function for thread pool case.
294 *
295 * This function receives an already created thread pool object and
296 * creates and runs http-server on this thread pool.
297 *
298 * \since
299 * v.0.4.2
300 */
301template<typename Io_Context_Holder, typename Traits>
302void
304 ioctx_on_thread_pool_t<Io_Context_Holder> & pool,
305 run_on_thread_pool_settings_t<Traits> && settings )
306{
307 using settings_t = run_on_thread_pool_settings_t<Traits>;
308 using server_t = http_server_t<Traits>;
309
310 server_t server{
311 restinio::external_io_context( pool.io_context() ),
312 std::forward<settings_t>(settings) };
313
314 std::exception_ptr exception_caught;
315
316 asio_ns::signal_set break_signals{ server.io_context(), SIGINT };
317 break_signals.async_wait(
318 [&]( const asio_ns::error_code & ec, int ){
319 if( !ec )
320 {
321 server.close_async(
322 [&]{
323 // Stop running io_service.
324 pool.stop();
325 },
326 [&exception_caught]( std::exception_ptr ex ){
327 // We can't throw an exception here!
328 // Store it to rethrow later.
329 exception_caught = ex;
330 } );
331 }
332 } );
333
334 server.open_async(
335 []{ /* Ok. */},
336 [&pool, &exception_caught]( std::exception_ptr ex ){
337 // Stop running io_service.
338 // We can't throw an exception here!
339 // Store it to rethrow later.
340 pool.stop();
341 exception_caught = ex;
342 } );
343
344 pool.start();
345 pool.wait();
346
347 // If an error was detected it should be propagated.
348 if( exception_caught )
349 std::rethrow_exception( exception_caught );
350}
351
352} /* namespace impl */
353
354//! Helper function for running http server until ctrl+c is hit.
355/*!
356 * This function creates its own instance of Asio's io_context and
357 * uses it exclusively.
358 *
359 * Usage example:
360 * \code
361 * restinio::run(
362 * restinio::on_thread_pool<my_traits>(4)
363 * .port(8080)
364 * .address("localhost")
365 * .request_handler([](auto req) {...}));
366 * \endcode
367 */
368template<typename Traits>
369inline void
370run( run_on_thread_pool_settings_t<Traits> && settings )
371{
372 using thread_pool_t = impl::ioctx_on_thread_pool_t<
374
375 thread_pool_t pool( settings.pool_size() );
376
377 impl::run( pool, std::move(settings) );
378}
379
380//! Helper function for running http server until ctrl+c is hit.
381/*!
382 * Can be useful when RESTinio server should be run on the user's
383 * own io_context instance.
384 *
385 * For example:
386 * \code
387 * asio::io_context iosvc;
388 * ... // iosvc used by user.
389 * restinio::run(iosvc,
390 * restinio::on_thread_pool<my_traits>(4)
391 * .port(8080)
392 * .address("localhost")
393 * .request_handler([](auto req) {...}));
394 * \endcode
395 *
396 * \since
397 * v.0.4.2
398 */
399template<typename Traits>
400inline void
402 //! Asio's io_context to be used.
403 //! Note: this reference should remain valid until RESTinio server finished.
404 asio_ns::io_context & ioctx,
405 //! Settings for that server instance.
406 run_on_thread_pool_settings_t<Traits> && settings )
407{
408 using thread_pool_t = impl::ioctx_on_thread_pool_t<
410
411 thread_pool_t pool{ settings.pool_size(), ioctx };
412
413 impl::run( pool, std::move(settings) );
414}
415
416//
417// run_existing_server_on_thread_pool_t
418//
419/*!
420 * @brief Helper type for holding parameters necessary for running
421 * HTTP-server on a thread pool.
422 *
423 * @note This class is not intended for direct use. It is used by
424 * RESTinio itself.
425 *
426 * @since v.0.5.1
427 */
428template<typename Traits>
430{
431 //! Size of thread pool.
432 std::size_t m_pool_size;
433 //! Should break signal handler be used?
435 //! HTTP-server to be used on a thread pool.
436 /*!
437 * We assume that this pointer will be valid pointer.
438 */
440
441public:
442 //! Initializing constructor.
444 //! Size of the pool.
445 std::size_t pool_size,
446 //! Should break signal handler be used?
447 break_signal_handling_t break_handling,
448 //! A reference to HTTP-server to be run on a thread pool.
449 //! This reference should outlive an instance of
450 //! run_existing_server_on_thread_pool_t.
451 http_server_t<Traits> & server )
452 : m_pool_size{ pool_size }
453 , m_break_handling{ break_handling }
454 , m_server{ &server }
455 {}
456
457 std::size_t
458 pool_size() const noexcept { return m_pool_size; }
459
461 break_handling() const noexcept { return m_break_handling; }
462
463 http_server_t<Traits> &
464 server() const noexcept { return *m_server; }
465};
466
467/*!
468 * @brief Helper function for running an existing HTTP-server on
469 * a thread pool.
470 *
471 * Usage example:
472 * @code
473 * using my_server_t = restinio::http_server_t< my_server_traits_t >;
474 * my_server_t server{
475 * restinio::own_io_context(),
476 * [](auto & settings) {
477 * settings.port(...);
478 * settings.address(...);
479 * settings.request_handler(...);
480 * ...
481 * }
482 * };
483 * ...
484 * restinio::run( restinio::on_thread_pool(
485 * std::thread::hardware_concurrency(),
486 * restinio::use_break_signal_handling(),
487 * server) );
488 * @endcode
489 *
490 * @since v.0.5.1
491 */
492template<typename Traits>
495 std::size_t pool_size,
496 break_signal_handling_t break_handling,
497 http_server_t<Traits> & server )
498{
499 return { pool_size, break_handling, server };
500}
501
502namespace impl {
503
504/*!
505 * \brief An implementation of run-function for thread pool case
506 * with existing http_server instance.
507 *
508 * This function receives an already created thread pool object and
509 * already created http-server and run it on this thread pool.
510 *
511 * \attention
512 * This function installs break signal handler and stops server when
513 * break signal is raised.
514 *
515 * \since
516 * v.0.5.1
517 */
518template<typename Io_Context_Holder, typename Traits>
519void
521 ioctx_on_thread_pool_t<Io_Context_Holder> & pool,
522 http_server_t<Traits> & server )
523{
524 std::exception_ptr exception_caught;
525
526 asio_ns::signal_set break_signals{ server.io_context(), SIGINT };
527 break_signals.async_wait(
528 [&]( const asio_ns::error_code & ec, int ){
529 if( !ec )
530 {
531 server.close_async(
532 [&]{
533 // Stop running io_service.
534 pool.stop();
535 },
536 [&exception_caught]( std::exception_ptr ex ){
537 // We can't throw an exception here!
538 // Store it to rethrow later.
539 exception_caught = ex;
540 } );
541 }
542 } );
543
544 server.open_async(
545 []{ /* Ok. */},
546 [&pool, &exception_caught]( std::exception_ptr ex ){
547 // Stop running io_service.
548 // We can't throw an exception here!
549 // Store it to rethrow later.
550 pool.stop();
551 exception_caught = ex;
552 } );
553
554 pool.start();
555 pool.wait();
556
557 // If an error was detected it should be propagated.
558 if( exception_caught )
559 std::rethrow_exception( exception_caught );
560}
561
562/*!
563 * \brief An implementation of run-function for thread pool case
564 * with existing http_server instance.
565 *
566 * This function receives an already created thread pool object and
567 * already created http-server and run it on this thread pool.
568 *
569 * \note
570 * This function doesn't install break signal handlers.
571 *
572 * \since
573 * v.0.5.1
574 */
575template<typename Io_Context_Holder, typename Traits>
576void
578 ioctx_on_thread_pool_t<Io_Context_Holder> & pool,
579 http_server_t<Traits> & server )
580{
581 std::exception_ptr exception_caught;
582
583 server.open_async(
584 []{ /* Ok. */},
585 [&pool, &exception_caught]( std::exception_ptr ex ){
586 // Stop running io_service.
587 // We can't throw an exception here!
588 // Store it to rethrow later.
589 pool.stop();
590 exception_caught = ex;
591 } );
592
593 pool.start();
594 pool.wait();
595
596 // If an error was detected it should be propagated.
597 if( exception_caught )
598 std::rethrow_exception( exception_caught );
599}
600
601} /* namespace impl */
602
603/*!
604 * @brief Helper function for running an existing HTTP-server on
605 * a thread pool.
606 *
607 * Usage example:
608 * @code
609 * using my_server_t = restinio::http_server_t< my_server_traits_t >;
610 * my_server_t server{
611 * restinio::own_io_context(),
612 * [](auto & settings) {
613 * settings.port(...);
614 * settings.address(...);
615 * settings.request_handler(...);
616 * ...
617 * }
618 * };
619 * ...
620 * // run() returns if Ctrl+C is pressed or if HTTP-server will
621 * // be shut down from elsewhere.
622 * restinio::run( restinio::on_thread_pool(
623 * std::thread::hardware_concurrency(),
624 * restinio::use_break_signal_handling(),
625 * server) );
626 * @endcode
627 *
628 * @since v.0.5.1
629 */
630template<typename Traits>
631inline void
633{
634 using thread_pool_t = impl::ioctx_on_thread_pool_t<
636
637 thread_pool_t pool{ params.pool_size(), params.server().io_context() };
638
639 if( break_signal_handling_t::used == params.break_handling() )
640 impl::run_with_break_signal_handling( pool, params.server() );
641 else
642 impl::run_without_break_signal_handling( pool, params.server() );
643}
644
645//
646// initiate_shutdown
647//
648/*!
649 * @brief Helper function for initiation of server shutdown.
650 *
651 * Can be useful if an existing HTTP-server is run via run() function.
652 * For example:
653 * @code
654 * restinio::http_server_t< my_traits > server{ ... };
655 * // Launch another thread that will perform some application logic.
656 * std::thread app_logic_thread{ [&server] {
657 * while(some_condition) {
658 * ...
659 * if(exit_case) {
660 * // HTTP-server should be shut down.
661 * restinio::initiate_shutdown( server );
662 * // Our work should be finished.
663 * return;
664 * }
665 * }
666 * } };
667 * // Start HTTP-server. The current thread will be blocked until
668 * // run() returns.
669 * restinio::run( restinio::on_thread_pool(
670 * 4,
671 * restinio::skip_break_signal_handling(),
672 * server) );
673 * // Now app_logic_thread can be joined.
674 * app_logic_thread.join();
675 * @endcode
676 *
677 * @since v.0.5.1
678 */
679template<typename Traits>
680inline void
682{
683 asio_ns::post(
684 server.io_context(),
685 [&server] {
686 server.close_sync();
687 server.io_context().stop();
688 } );
689}
690
691/*!
692 * @brief Type of a function to be used as the default on_error-callback.
693 *
694 * Since v.0.7.0 on_pool_runner_t::stop() accept a on_error callback that
695 * will be passed to http_server_t::close_async() and will be called if
696 * an exception is thrown in http_server_t::close_async().
697 * This callback should perform some actions that can help the application
698 * to handle the problem.
699 *
700 * This type is intended to be used as the default on_error callback.
701 *
702 * If an exception in thrown inside http_server_t::close_async() then
703 * the application is in undefined state, it's unknown what can be done
704 * with http_server_t instance and whan can't be.
705 *
706 * Therefore the default on_error callback simply calls std::abort() to
707 * terminate the application and avoid the work in undefined state.
708 *
709 * If such behavour is not desirable the user can provide own
710 * on_error callback.
711 *
712 * @since v.0.7.0
713 */
715{
716 /*!
717 * @attention
718 * It just calls std::abort().
719 */
720 [[noreturn]]
721 void
722 operator()( std::exception_ptr /*ex*/ ) const noexcept
723 {
724 std::abort();
725 }
726};
727
728//
729// on_pool_runner_t
730//
731/*!
732 * @brief Helper class for running an existing HTTP-server on a thread pool
733 * without blocking the current thread.
734 *
735 * Usage of run() functions has some drawbacks. For example, the current thread
736 * on that run() is called, will be blocked until run() returns.
737 *
738 * Sometimes it is not appropriate and leads to tricks like that:
739 * @code
740 * // HTTP-server to be run on a thread pool.
741 * restinio::http_server_t< my_traits > server{...};
742 *
743 * // Separate worker thread for calling restinio::run().
744 * std::thread run_thread{ [&server] {
745 * restinio::run( restinio::on_thread_pool(
746 * 16,
747 * restinio::skip_break_signal_handling(),
748 * server) );
749 * // Now this thread is blocked until HTTP-server will be finished.
750 * } };
751 *
752 * ... // Some application specific code here.
753 *
754 * // Now the server can be stopped.
755 * restinio::initiate_shutdown( server );
756 * run_thread.join();
757 * @endcode
758 *
759 * Writing such code is a boring and error-prone task. The class
760 * on_pool_runner_t can be used instead:
761 * @code
762 * // HTTP-server to be run on a thread pool.
763 * restinio::http_server_t< my_traits > server{...};
764 *
765 * // Launch HTTP-server on a thread pool.
766 * restinio::on_pool_runner_t< restinio::http_server_t<my_traits> > runner{
767 * 16,
768 * server
769 * };
770 * runner.start();
771 *
772 * ... // Some application specific code here.
773 *
774 * // Now the server can be stopped.
775 * runner.stop(); // (1)
776 * runner.wait();
777 * @endcode
778 *
779 * Moreover the code at point (1) in the example above it not necessary
780 * because on_pool_runner_t automatically stops the server in the destructor.
781 *
782 * @since v.0.5.1
783 */
784template<typename Http_Server>
786{
787 //! HTTP-server to be run.
788 Http_Server & m_server;
789
790 //! Thread pool for running the server.
793
794public :
797
798 //! Initializing constructor.
800 //! Size of thread pool.
801 std::size_t pool_size,
802 //! Server instance to be run.
803 //! NOTE. This reference must be valid for all life-time
804 //! of on_pool_runner instance.
805 Http_Server & server )
806 : m_server{ server }
808 {}
809
810 /*!
811 * @brief Start the server with callbacks that will be called on
812 * success or failure.
813 *
814 * The @a on_ok should be a function/functor with the format:
815 * @code
816 * void () noexcept;
817 * @endcode
818 *
819 * The @a on_error should be a function/functor with the format:
820 * @code
821 * void (std::exception_ptr) noexcept;
822 * @endcode
823 *
824 * @note
825 * Both callbacks will be passed to http_server_t::open_async method.
826 * It means that @a on_error callback will be called for errors detected
827 * by open_async() methods.
828 *
829 * @attention
830 * Both callbacks should be noexcept functions/functors.
831 *
832 * Usage example:
833 * @code
834 * using my_http_server = restinio::http_server_t<some_traits>;
835 *
836 * my_http_server server{...};
837 * restinio::on_pool_runner_t<my_http_server> runner{16, server};
838 *
839 * std::promise<void> run_promise;
840 * auto run_future = run_promise.get_future();
841 * runner.start(
842 * // Ok callback.
843 * [&run_promise]() noexcept {
844 * run_promise.set_value();
845 * },
846 * // Error callback.
847 * [&run_promise](std::exception_ptr ex) noexcept {
848 * run_promise.set_exception(std::move(ex));
849 * });
850 * // Wait while HTTP-server started (or start failed).
851 * run_future.get();
852 * @endcode
853 *
854 * @since v.0.6.7
855 */
856 template<
857 typename On_Ok_Callback,
858 typename On_Error_Callback >
859 void
861 //! A callback to be called if HTTP-server started successfully.
862 On_Ok_Callback && on_ok,
863 //! A callback to be called if HTTP-server is not started by
864 //! some reasons. Please note that this callback is passed
865 //! to http_server_t::open_async() and will be called only
866 //! for errors detected by open_async() methods.
867 //! If some error is detected outside of open_async() (for
868 //! example a failure to start a thread pool) then on_error
869 //! callback won't be called.
870 On_Error_Callback && on_error )
871 {
872 static_assert( noexcept(on_ok()), "On_Ok_Callback should be noexcept" );
873 static_assert( noexcept(on_error(std::declval<std::exception_ptr>())),
874 "On_Error_Callback should be noexcept" );
875
876 m_server.open_async(
877 [callback = std::move(on_ok)]() noexcept { callback(); },
878 [this, callback = std::move(on_error)]( std::exception_ptr ex ) noexcept {
879 // There is no sense to run pool.
880 m_pool.stop();
881
882 callback( std::move(ex) );
883 } );
884
885 m_pool.start();
886 }
887
888 //! Start the server.
889 /*!
890 * It just a shorthand for a version of `start` method with callbacks
891 * where all callbacks to nothing.
892 */
893 void
895 {
896 this->start(
897 []() noexcept { /* nothing to do */ },
898 []( std::exception_ptr ) noexcept { /* nothing to do */ } );
899 }
900
901 //! Is server started.
902 bool
903 started() const noexcept { return m_pool.started(); }
904
905 //! Stop the server.
906 /*!
907 * This method stops the server by calling http_server_t::close_async()
908 * It means that stop will be performed asynchronously. To wait for the
909 * completion of stop operation the wait() method has to be used.
910 *
911 * The simple usage:
912 * @code
913 * using my_http_server = restinio::http_server_t<some_traits>;
914 *
915 * my_http_server server{...};
916 * restinio::on_pool_runner_t<my_http_server> runner{16, server};
917 *
918 * runner.start(...);
919 *
920 * ...
921 * // Some time later.
922 * runner.stop();
923 *
924 * ... // Some other actions.
925 * // Have to wait the completion of the stop() operation.
926 * runner.wait();
927 * @endcode
928 *
929 * This method accepts @a error_cb callback that will be called
930 * if an exception is thrown in http_server_t::close_async().
931 *
932 * The @a error_cb is an optional parameter, an instance of
933 * abort_app_in_error_callback_t is used by default. It means that
934 * if an exception is thrown on http_server_t::close_async() then
935 * the whole application will be terminated. If such behavior is not
936 * desirable a user has to provide own error callback:
937 * @code
938 * using my_http_server = restinio::http_server_t<some_traits>;
939 *
940 * my_http_server server{...};
941 * restinio::on_pool_runner_t<my_http_server> runner{16, server};
942 *
943 * runner.start(...);
944 *
945 * ...
946 * // Some time later.
947 * runner.stop([](std::exception_ptr ex) {
948 * ... // Some handling of an exception.
949 * });
950 * @endcode
951 * But it's important to note that if an exception is thrown inside
952 * http_server_t::close_async() then the instance of http_server_t
953 * is in undefined state.
954 *
955 * @note
956 * This method is noexcept since v.0.6.7
957 *
958 * @tparam Error_CB Type of the callback to be used if an exception
959 * is thrown inside http_server_t::close_async(). This callback
960 * should be noexcept functor (however, the noexceptness is not
961 * checked at the compile-time to have a possibility to use
962 * std::function as error callback). See abort_app_in_error_callback_t
963 * for a prototype of Error_CB functor.
964 */
965 template< typename Error_CB = abort_app_in_error_callback_t >
966 void
967 stop( Error_CB error_cb = Error_CB{} ) noexcept
968 {
969 // NOTE: m_pool.stop() call be called only inside lambda-functions
970 // because they may be executed some time later after the return
971 // from close_async().
972 m_server.close_async(
973 [this]() noexcept {
974 // Stop running io_service.
975 m_pool.stop();
976 },
977 [this, callback = std::move(error_cb)]( std::exception_ptr ex ) noexcept {
978 // Stop running io_service anyway.
979 m_pool.stop();
980
981 // We have to call error_cb in this case.
982 callback( std::move(ex) );
983 } );
984 }
985
986 //! Wait for full stop of the server.
987 /*!
988 * @note
989 * This method is noexcept since v.0.6.7
990 */
991 void
992 wait() noexcept { m_pool.wait(); }
993};
994
995// Forward declaration.
996// It's necessary for running_server_handle_t.
997template< typename Http_Server >
999
1000//
1001// running_server_handle_t
1002//
1003/*!
1004 * @brief The type to be used as a handle for running server instance.
1005 *
1006 * The handle should be seen as a Moveable and not Copyable type.
1007 *
1008 * @since v.0.6.7
1009 */
1010template< typename Traits >
1013
1014//
1015// running_server_instance_t
1016//
1017/*!
1018 * @brief A helper class used in an implementation of #run_async function.
1019 *
1020 * An instance of that class holds an HTTP-server and thread pool on that
1021 * this HTTP-server is launched.
1022 *
1023 * The HTTP-server will automatically be stopped in the destructor.
1024 * However, a user can stop the HTTP-server manually by using
1025 * stop() and wait() methods.
1026 *
1027 * @since v.0.6.7
1028 */
1029template< typename Http_Server >
1031{
1032 template< typename Traits >
1034 run_async(
1036 server_settings_t<Traits> &&,
1037 std::size_t thread_pool_size );
1038
1039 //! Actual server instance.
1040 Http_Server m_server;
1041
1042 //! The runner of the server.
1044
1045 //! Initializing constructor.
1047 io_context_holder_t io_context,
1048 server_settings_t< typename Http_Server::traits_t > && settings,
1049 std::size_t thread_pool_size )
1050 : m_server{ std::move(io_context), std::move(settings) }
1051 , m_runner{ thread_pool_size, m_server }
1052 {}
1053
1054
1055 //! Start the HTTP-server.
1056 /*!
1057 * Returns when HTTP-server started or some startup failure detected.
1058 * It means that the caller thread will be blocked until HTTP-server
1059 * calls on_ok or on_error callback.
1060 *
1061 * Throws an exception on an error.
1062 */
1063 void
1065 {
1066 std::promise<void> p;
1067 auto f = p.get_future();
1068 m_runner.start(
1069 [&p]() noexcept { p.set_value(); },
1070 [&p]( std::exception_ptr ex ) noexcept {
1071 p.set_exception( std::move(ex) );
1072 } );
1073 f.get();
1074 }
1075
1076public :
1077 /*!
1078 * Stop the HTTP-server.
1079 *
1080 * This method initiates shutdown procedure that can take some
1081 * time. But stop() returns without the waiting for the completeness
1082 * of the shutdown. To wait for the completeness use wait() method:
1083 *
1084 * @code
1085 * auto server = restinio::run_async(...);
1086 * ...
1087 * server->stop(); // Returns without the waiting.
1088 * ... // Some other actions.
1089 * server->wait(); // Returns only when HTTP-server stopped.
1090 * @endcode
1091 *
1092 * @attention
1093 * The current version doesn't guarantee that stop() can be called
1094 * safely several times. Please take care of that and call stop()
1095 * only once.
1096 */
1097 void
1098 stop() noexcept
1099 {
1100 m_runner.stop();
1101 }
1102
1103 /*!
1104 * @brief Wait for the shutdown of HTTP-server.
1105 *
1106 * @note
1107 * Method stop() should be called before the call to wait():
1108 * @code
1109 * auto server = restinio::run_async(...);
1110 * ...
1111 * server->stop(); // Initiates the shutdown and returns without the waiting.
1112 * server->wait(); // Returns only when HTTP-server stopped.
1113 * @endcode
1114 *
1115 * @attention
1116 * The current version doesn't guarantee that wait() can be called
1117 * safely several times. Please take care of that and call wait()
1118 * only once.
1119 */
1120 void
1121 wait() noexcept
1122 {
1123 m_runner.wait();
1124 }
1125};
1126
1127//
1128// run_async
1129//
1130/*!
1131 * @brief Creates an instance of HTTP-server and launches it on a
1132 * separate thread or thread pool.
1133 *
1134 * Usage example:
1135 * @code
1136 * int main() {
1137 * auto server = restinio::run_async(
1138 * // Asio's io_context to be used.
1139 * // HTTP-server will use own Asio's io_context object.
1140 * restinio::own_io_context(),
1141 * // The settings for the HTTP-server.
1142 * restinio::server_settings_t{}
1143 * .address("127.0.0.1")
1144 * .port(8080)
1145 * .request_handler(...),
1146 * // The size of thread-pool for the HTTP-server.
1147 * 16);
1148 * // If we are here and run_async doesn't throw then HTTP-server
1149 * // is started.
1150 *
1151 * ... // Some other actions.
1152 *
1153 * // No need to stop HTTP-server manually. It will be automatically
1154 * // stopped in the destructor of `server` object.
1155 * }
1156 * @endcode
1157 * Or, if user-defined traits should be used:
1158 * @code
1159 * int main() {
1160 * struct my_traits : public restinio::default_traits_t {
1161 * ...
1162 * };
1163 *
1164 * auto server = restinio::run_async<my_traits>(
1165 * restinio::own_io_context(),
1166 * restinio::server_settings_t<my_traits>{}
1167 * .address(...)
1168 * .port(...)
1169 * .request_handler(...),
1170 * // Use just one thread for the HTTP-server.
1171 * 1u);
1172 *
1173 * ... // Some other actions.
1174 * }
1175 * @endcode
1176 *
1177 * run_async() returns control when HTTP-server is started or some
1178 * startup failure is detected. But if a failure is detected then an
1179 * exception is thrown. So if run_async() returns successfuly then
1180 * HTTP-server is working.
1181 *
1182 * The started HTTP-server will be automatically stopped at the
1183 * destruction of the returned value. Because of that the returned
1184 * value should be stored for the time while HTTP-server is needed.
1185 *
1186 * The started HTTP-server can be stopped manually by calling
1187 * stop() and wait() methods:
1188 * @code
1189 * auto server = restinio::run_async(...);
1190 * ...
1191 * server->stop(); // Returns without the waiting.
1192 * ... // Some other actions.
1193 * server->wait(); // Returns only when HTTP-server stopped.
1194 * @endcode
1195 *
1196 * @since v.0.6.7
1197 */
1198template< typename Traits = default_traits_t >
1199[[nodiscard]]
1202 io_context_holder_t io_context,
1203 server_settings_t< Traits > && settings,
1204 std::size_t thread_pool_size )
1205{
1206 running_server_handle_t< Traits > handle{
1208 std::move(io_context),
1209 std::move(settings),
1210 thread_pool_size }
1211 };
1212
1213 handle->start();
1214
1215 return handle;
1216}
1217
1218} /* namespace restinio */
Basic container for http_server settings.
Definition settings.hpp:555
Class for http-server.
A class for holding a reference to external Asio's io_context.
A class for holding actual instance of Asio's io_context.
Helper class for holding shared pointer to io_context.
Helper class for running an existing HTTP-server on a thread pool without blocking the current thread...
void wait() noexcept
Wait for full stop of the server.
void start()
Start the server.
on_pool_runner_t(std::size_t pool_size, Http_Server &server)
Initializing constructor.
impl::ioctx_on_thread_pool_t< impl::external_io_context_for_thread_pool_t > m_pool
Thread pool for running the server.
on_pool_runner_t(const on_pool_runner_t &)=delete
bool started() const noexcept
Is server started.
void start(On_Ok_Callback &&on_ok, On_Error_Callback &&on_error)
Start the server with callbacks that will be called on success or failure.
void stop(Error_CB error_cb=Error_CB{}) noexcept
Stop the server.
on_pool_runner_t(on_pool_runner_t &&)=delete
Http_Server & m_server
HTTP-server to be run.
Helper type for holding parameters necessary for running HTTP-server on a thread pool.
http_server_t< Traits > * m_server
HTTP-server to be used on a thread pool.
break_signal_handling_t m_break_handling
Should break signal handler be used?
break_signal_handling_t break_handling() const noexcept
run_existing_server_on_thread_pool_t(std::size_t pool_size, break_signal_handling_t break_handling, http_server_t< Traits > &server)
Initializing constructor.
http_server_t< Traits > & server() const noexcept
basic_server_settings_t< run_on_this_thread_settings_t< Traits >, Traits > base_type_t
std::size_t m_pool_size
Size of the pool.
std::size_t pool_size() const
Get the pool size.
run_on_thread_pool_settings_t(std::size_t pool_size)
Constructor.
A helper class used in an implementation of run_async function.
void start()
Start the HTTP-server.
void wait() noexcept
Wait for the shutdown of HTTP-server.
friend running_server_handle_t< Traits > run_async(io_context_holder_t, server_settings_t< Traits > &&, std::size_t thread_pool_size)
Creates an instance of HTTP-server and launches it on a separate thread or thread pool.
Http_Server m_server
Actual server instance.
running_server_instance_t(io_context_holder_t io_context, server_settings_t< typename Http_Server::traits_t > &&settings, std::size_t thread_pool_size)
Initializing constructor.
on_pool_runner_t< Http_Server > m_runner
The runner of the server.
void run_without_break_signal_handling(ioctx_on_thread_pool_t< Io_Context_Holder > &pool, http_server_t< Traits > &server)
An implementation of run-function for thread pool case with existing http_server instance.
void run(ioctx_on_thread_pool_t< Io_Context_Holder > &pool, run_on_thread_pool_settings_t< Traits > &&settings)
An implementation of run-function for thread pool case.
void run_with_break_signal_handling(ioctx_on_thread_pool_t< Io_Context_Holder > &pool, http_server_t< Traits > &server)
An implementation of run-function for thread pool case with existing http_server instance.
constexpr break_signal_handling_t skip_break_signal_handling() noexcept
Make the indicator for absence of break signal handler.
run_existing_server_on_thread_pool_t< Traits > on_thread_pool(std::size_t pool_size, break_signal_handling_t break_handling, http_server_t< Traits > &server)
Helper function for running an existing HTTP-server on a thread pool.
run_on_thread_pool_settings_t< Traits > on_thread_pool(std::size_t pool_size)
A special marker for the case when http_server must be run on an thread pool.
void run(run_on_this_thread_settings_t< Traits > &&settings)
Helper function for running http server until ctrl+c is hit.
run_on_this_thread_settings_t< Traits > on_this_thread()
A special marker for the case when http_server must be run on the context of the current thread.
io_context_holder_t external_io_context(asio_ns::io_context &ctx)
Function which tells that http_server should use external instance of io_context and should not contr...
running_server_handle_t< Traits > run_async(io_context_holder_t io_context, server_settings_t< Traits > &&settings, std::size_t thread_pool_size)
Creates an instance of HTTP-server and launches it on a separate thread or thread pool.
void run(run_on_thread_pool_settings_t< Traits > &&settings)
Helper function for running http server until ctrl+c is hit.
void run(asio_ns::io_context &ioctx, run_on_thread_pool_settings_t< Traits > &&settings)
Helper function for running http server until ctrl+c is hit.
constexpr break_signal_handling_t use_break_signal_handling() noexcept
Make the indicator for usage of break signal handler.
void run(run_existing_server_on_thread_pool_t< Traits > &&params)
Helper function for running an existing HTTP-server on a thread pool.
void run(asio_ns::io_context &ioctx, run_on_this_thread_settings_t< Traits > &&settings)
Helper function for running http server until ctrl+c is hit.
break_signal_handling_t
Indication of usage of break signal handlers for some forms of run functions.
@ used
Signal handler should be used by run() function.
@ skipped
Signal handler should not be used by run() function.
void initiate_shutdown(http_server_t< Traits > &server)
Helper function for initiation of server shutdown.
Type of a function to be used as the default on_error-callback.
void operator()(std::exception_ptr) const noexcept