summaryrefslogtreecommitdiff
path: root/common/src/http_healthcheck.cpp
blob: f36d59f7fb1f7c60e67aee76ba84029668e59616 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#include <string.h>
#include <limits.h>
#include <pthread.h>

#include "event2/event.h"
#include "event2/buffer.h"
#include "event2/http.h"
#include "http_healthcheck.h"
#include <MESA/MESA_prof_load.h>

struct http_status_ctx
{
	pthread_t pthread;
	struct event_base *base;
	struct event *ev;
	struct evhttp *http;

	unsigned int enable;
	unsigned int port;
	char addr[PATH_MAX];
	char path[PATH_MAX];
	uint64_t is_error;
} g_ctx = {0};

static void http_callback(struct evhttp_request *req, void *arg)
{
	evhttp_send_reply(req, HTTP_OK, "", NULL);
}

static void gc_callback(evutil_socket_t fd, short what, void *arg)
{
	// do nothing

	// add gc_callback to avoid event_base_dispatch blocking, handle event_base_loopbreak inmediately
}

static void *http_healthcheck_thread(void *arg)
{
	struct timeval gc_delay = {0, 500 * 1000}; // Microseconds, we set 500 miliseconds here.
	printf("[http_healthcheck_thread]: running (listen: %s:%d path: %s)\n", g_ctx.addr, g_ctx.port, g_ctx.path);

	g_ctx.base = event_base_new();
	if (g_ctx.base == NULL)
	{
		printf("[http_healthcheck_thread]: event_base_new failed\n");
		goto end;
	}

	g_ctx.ev = event_new(g_ctx.base, -1, EV_PERSIST, gc_callback, NULL);
	if (g_ctx.ev == NULL)
	{
		printf("[http_healthcheck_thread]: event_new failed\n");
		goto end;
	}

	if (evtimer_add(g_ctx.ev, &gc_delay) < 0)
	{
		printf("[http_healthcheck_thread]: evtimer_add failed\n");
		goto end;
	}

	g_ctx.http = evhttp_new(g_ctx.base);
	if (evhttp_set_cb(g_ctx.http, g_ctx.path, http_callback, NULL) < 0)
	{
		printf("[http_healthcheck_thread]: evhttp_set_cb failed\n");
		goto end;
	}

	if (evhttp_bind_socket(g_ctx.http, g_ctx.addr, g_ctx.port) < 0)
	{
		printf("[http_healthcheck_thread]: evhttp_bind_socket failed\n");
		goto end;
	}
	event_base_dispatch(g_ctx.base);

end:
	if (g_ctx.http)
	{
		evhttp_free(g_ctx.http);
	}
	if (g_ctx.ev)
	{
		event_free(g_ctx.ev);
	}
	if (g_ctx.base)
	{
		event_base_free(g_ctx.base);
	}

	printf("[http_healthcheck_thread]: exit\n");
	return NULL;
}

void http_healthcheck_server_start(const char *profile)
{
	MESA_load_profile_uint_def(profile, "http_healthcheck_server", "enable", &g_ctx.enable, 0);
	MESA_load_profile_uint_def(profile, "http_healthcheck_server", "port", &g_ctx.port, 8080);
	MESA_load_profile_string_def(profile, "http_healthcheck_server", "addr", g_ctx.addr, sizeof(g_ctx.addr), "127.0.0.1");
	MESA_load_profile_string_def(profile, "http_healthcheck_server", "path", g_ctx.path, sizeof(g_ctx.path), "/status");

	if (!g_ctx.enable)
	{
		return;
	}

	pthread_create(&g_ctx.pthread, NULL, http_healthcheck_thread, (void *)&g_ctx);
}

void http_healthcheck_server_stop()
{
	if (g_ctx.enable)
	{
		event_base_loopbreak(g_ctx.base);
		pthread_join(g_ctx.pthread, NULL);
	}
}