ACLK timeout (#19425)
* fix aclk timeout * added workers to aclk thread
Costa Tsaousis committed
Jan 17, 2025 at 13:02 UTC
ccbae3ab031dc34f7959c566612bfb0262c90667
7 files changed
+114
-13
CMakeLists.txt
+1
@@ -1900,6 +1900,7 @@ set(MQTT_WEBSOCKETS_FILES
1900
src/aclk/mqtt_websockets/common_public.c
1901
src/aclk/mqtt_websockets/common_public.h
1902
src/aclk/mqtt_websockets/common_internal.h
1903
+ src/aclk/mqtt_websockets/aclk_mqtt_workers.h
1904
)
1905
1906
set(ACLK_PROTO_DEFS
src/aclk/aclk.c
+37
@@ -3,6 +3,7 @@
3
#include "aclk.h"
4
5
#include "mqtt_websockets/mqtt_wss_client.h"
6
+#include "mqtt_websockets/aclk_mqtt_workers.h"
7
#include "aclk_otp.h"
8
#include "aclk_tx_msgs.h"
9
#include "aclk_query.h"
@@ -307,6 +308,7 @@ static int handle_connection(mqtt_wss_client client)
308
// timeout 1000 to check at least once a second
309
// for netdata_exit
310
if (mqtt_wss_service(client, 1000) < 0){
311
+ worker_is_busy(WORKER_ACLK_DISCONNECTED);
312
error_report("Connection Error or Dropped");
313
return 1;
314
}
@@ -315,16 +317,20 @@ static int handle_connection(mqtt_wss_client client)
317
const char *reason;
318
switch (disconnect_req) {
319
case ACLK_CLOUD_DISCONNECT:
320
+ worker_is_busy(WORKER_ACLK_CMD_DISCONNECT);
321
reason = "cloud request";
322
break;
323
case ACLK_PING_TIMEOUT:
324
+ worker_is_busy(WORKER_ACLK_CMD_TIMEOUT);
325
reason = "ping timeout";
326
schedule_node_update = true;
327
break;
328
case ACLK_RELOAD_CONF:
329
+ worker_is_busy(WORKER_ACLK_CMD_RELOAD_CONF);
330
reason = "reclaim";
331
break;
332
default:
333
+ worker_is_busy(WORKER_ACLK_CMD_UNKNOWN);
334
reason = "unknown";
335
break;
336
}
@@ -769,6 +775,31 @@ void *aclk_main(void *ptr)
775
{
776
struct netdata_static_thread *static_thread = ptr;
777
778
+ worker_register("ACLK");
779
+ worker_register_job_name(WORKER_ACLK_WAIT_CLAIMING, "wait claim");
780
+ worker_register_job_name(WORKER_ACLK_CONNECT, "connect");
781
+ worker_register_job_name(WORKER_ACLK_NODE_UPDATE, "node update");
782
+ worker_register_job_name(WORKER_ACLK_HANDLE_CONNECTION, "handle connection");
783
+ worker_register_job_name(WORKER_ACLK_DISCONNECTED, "disconnected");
784
+ worker_register_job_name(WORKER_ACLK_CMD_DISCONNECT, "cmd disconnect");
785
+ worker_register_job_name(WORKER_ACLK_CMD_TIMEOUT, "cmd timeout");
786
+ worker_register_job_name(WORKER_ACLK_CMD_RELOAD_CONF, "cmd reload");
787
+ worker_register_job_name(WORKER_ACLK_CMD_UNKNOWN, "cmd unknown");
788
+ worker_register_job_name(WORKER_ACLK_SENT_PING, "sent ping");
789
+ worker_register_job_name(WORKER_ACLK_POLL_ERROR, "poll error");
790
+ worker_register_job_name(WORKER_ACLK_POLL_OK, "poll ok");
791
+ worker_register_job_name(WORKER_ACLK_RX, "rx");
792
+ worker_register_job_name(WORKER_ACLK_RX_ERROR, "rx error");
793
+ worker_register_job_name(WORKER_ACLK_PROCESS_RAW, "p-raw");
794
+ worker_register_job_name(WORKER_ACLK_PROCESS_HANDSHAKE, "p-handshake");
795
+ worker_register_job_name(WORKER_ACLK_PROCESS_ESTABLISHED, "p-established");
796
+ worker_register_job_name(WORKER_ACLK_PROCESS_ERROR, "p-error");
797
+ worker_register_job_name(WORKER_ACLK_PROCESS_CLOSED_GRACEFULLY, "p-closed");
798
+ worker_register_job_name(WORKER_ACLK_PROCESS_UNKNOWN, "p-unknown");
799
+ worker_register_job_name(WORKER_ACLK_HANDLE_MQTT_INTERNAL, "mqtt internal");
800
+ worker_register_job_name(WORKER_ACLK_TX, "tx");
801
+ worker_register_job_name(WORKER_ACLK_TX_ERROR, "tx error");
802
+
803
ACLK_PROXY_TYPE proxy_type;
804
aclk_get_proxy(&proxy_type);
805
if (proxy_type == PROXY_TYPE_SOCKS5) {
@@ -779,6 +810,7 @@ void *aclk_main(void *ptr)
810
811
aclk_init_rx_msg_handlers();
812
813
+ worker_is_busy(WORKER_ACLK_WAIT_CLAIMING);
814
if (wait_till_agent_claim_ready())
815
goto exit;
816
@@ -809,21 +841,26 @@ void *aclk_main(void *ptr)
841
netdata_log_info("Starting ACLK query event loop");
842
aclk_query_init(mqttwss_client);
843
do {
844
+ worker_is_busy(WORKER_ACLK_CONNECT);
845
if (aclk_attempt_to_connect(mqttwss_client))
846
goto exit_full;
847
848
if (schedule_node_update) {
849
+ worker_is_busy(WORKER_ACLK_NODE_UPDATE);
850
schedule_node_state_update(localhost, 0);
851
schedule_node_update = false;
852
}
853
854
+ worker_is_busy(WORKER_ACLK_HANDLE_CONNECTION);
855
if (handle_connection(mqttwss_client)) {
856
+ worker_is_busy(WORKER_ACLK_DISCONNECTED);
857
last_disconnect_time = now_realtime_sec();
858
aclk_set_disconnected();
859
nd_log(NDLS_ACCESS, NDLP_WARNING, "ACLK DISCONNECTED");
860
}
861
} while (service_running(SERVICE_ACLK));
862
863
+ worker_is_busy(WORKER_ACLK_DISCONNECTED);
864
aclk_graceful_disconnect(mqttwss_client);
865
866
#ifdef MQTT_WSS_DEBUG
src/aclk/mqtt_websockets/aclk_mqtt_workers.h
new
+30
@@ -0,0 +1,30 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+#ifndef NETDATA_ACLK_MQTT_WORKERS_H
4
+#define NETDATA_ACLK_MQTT_WORKERS_H
5
+
6
+#define WORKER_ACLK_WAIT_CLAIMING 0
7
+#define WORKER_ACLK_CONNECT 1
8
+#define WORKER_ACLK_NODE_UPDATE 2
9
+#define WORKER_ACLK_HANDLE_CONNECTION 3
10
+#define WORKER_ACLK_DISCONNECTED 4
11
+#define WORKER_ACLK_CMD_DISCONNECT 5
12
+#define WORKER_ACLK_CMD_TIMEOUT 6
13
+#define WORKER_ACLK_CMD_RELOAD_CONF 7
14
+#define WORKER_ACLK_CMD_UNKNOWN 8
15
+#define WORKER_ACLK_SENT_PING 9
16
+#define WORKER_ACLK_POLL_ERROR 10
17
+#define WORKER_ACLK_POLL_OK 11
18
+#define WORKER_ACLK_RX 12
19
+#define WORKER_ACLK_RX_ERROR 13
20
+#define WORKER_ACLK_PROCESS_RAW 14
21
+#define WORKER_ACLK_PROCESS_HANDSHAKE 15
22
+#define WORKER_ACLK_PROCESS_ESTABLISHED 16
23
+#define WORKER_ACLK_PROCESS_ERROR 17
24
+#define WORKER_ACLK_PROCESS_CLOSED_GRACEFULLY 18
25
+#define WORKER_ACLK_PROCESS_UNKNOWN 19
26
+#define WORKER_ACLK_HANDLE_MQTT_INTERNAL 20
27
+#define WORKER_ACLK_TX 21
28
+#define WORKER_ACLK_TX_ERROR 22
29
+
30
+#endif //NETDATA_ACLK_MQTT_WORKERS_H
src/aclk/mqtt_websockets/mqtt_wss_client.c
+37
-11
@@ -5,6 +5,7 @@
5
#endif
6
7
#include "libnetdata/libnetdata.h"
8
+#include "aclk_mqtt_workers.h"
9
#include "mqtt_wss_client.h"
10
#include "mqtt_ng.h"
11
#include "ws_client.h"
@@ -616,7 +617,7 @@ int mqtt_wss_connect(
617
client->poll_fds[POLLFD_SOCKET].events = POLLIN;
618
// wait till MQTT connection is established
619
while (!client->mqtt_connected) {
619
- if(mqtt_wss_service(client, -1)) {
620
+ if(mqtt_wss_service(client, 60 * MSEC_PER_SEC)) {
621
nd_log(NDLS_DAEMON, NDLP_ERR, "Error connecting to MQTT WSS server \"%s\", port %d.", host, port);
622
return 2;
623
}
@@ -661,13 +662,13 @@ static const char *mqtt_wss_error_tos(int ec)
662
663
static int mqtt_wss_service_all(mqtt_wss_client client, int timeout_ms)
664
{
664
- uint64_t exit_by = boottime_usec() + (timeout_ms * NSEC_PER_MSEC);
665
+ uint64_t exit_by_us = boottime_usec() + (timeout_ms * NSEC_PER_MSEC);
666
client->poll_fds[POLLFD_SOCKET].events |= POLLOUT; // TODO when entering mwtt_wss_service use out buffer size to arm POLLOUT
667
while (rbuf_bytes_available(client->ws_client->buf_write)) {
667
- const uint64_t now = boottime_usec();
668
- if (now >= exit_by)
668
+ const uint64_t now_us = boottime_usec();
669
+ if (now_us >= exit_by_us)
670
return MWS_TIMED_OUT;
670
- if (mqtt_wss_service(client, exit_by - now))
671
+ if (mqtt_wss_service(client, (exit_by_us - now_us) / USEC_PER_SEC))
672
return MWS_ERROR;
673
}
674
return MWS_OK;
@@ -753,9 +754,23 @@ static int handle_mqtt_internal(mqtt_wss_client client)
754
755
static int t_till_next_keepalive_ms(mqtt_wss_client client)
756
{
756
- time_t last_send = mqtt_ng_last_send_time(client->mqtt);
757
- time_t next_mqtt_keep_alive = last_send + client->mqtt_keepalive * 0.75;
758
- return ((next_mqtt_keep_alive - now_realtime_sec()) * MSEC_PER_SEC);
757
+ time_t last_send_ts = mqtt_ng_last_send_time(client->mqtt);
758
+ time_t next_mqtt_keep_alive_ts = last_send_ts + client->mqtt_keepalive * 0.75;
759
+
760
+ time_t now_ts = now_realtime_sec();
761
+
762
+ if(now_ts >= next_mqtt_keep_alive_ts)
763
+ return 0;
764
+
765
+ int timeout_ms = (int)((next_mqtt_keep_alive_ts - now_ts) * MSEC_PER_SEC);
766
+
767
+ if(timeout_ms < 1)
768
+ timeout_ms = 1;
769
+
770
+ if(timeout_ms > (int)(45 * MSEC_PER_SEC))
771
+ timeout_ms = (int)(45 * MSEC_PER_SEC);
772
+
773
+ return timeout_ms;
774
}
775
776
#ifdef MQTT_WSS_CPUSTATS
@@ -784,8 +799,6 @@ int mqtt_wss_service(mqtt_wss_client client, int timeout_ms)
799
// Check user requested TO doesn't interfere with MQTT keep alives
800
if (!ping_timeout) {
801
int till_next_keep_alive = t_till_next_keepalive_ms(client);
787
- if (till_next_keep_alive < 0)
788
- till_next_keep_alive = 0;
802
if (client->mqtt_connected && (timeout_ms < 0 || timeout_ms >= till_next_keep_alive)) {
803
timeout_ms = till_next_keep_alive;
804
send_keepalive = 1;
@@ -797,7 +810,10 @@ int mqtt_wss_service(mqtt_wss_client client, int timeout_ms)
810
client->stats.time_keepalive += t2 - t1;
811
#endif
812
813
+ worker_is_idle();
814
if ((ret = poll(client->poll_fds, 2, timeout_ms >= 0 ? timeout_ms : -1)) < 0) {
815
+ worker_is_busy(WORKER_ACLK_POLL_ERROR);
816
+
817
if (errno == EINTR) {
818
nd_log(NDLS_DAEMON, NDLP_WARNING, "poll interrupted by EINTR");
819
return 0;
@@ -805,6 +821,7 @@ int mqtt_wss_service(mqtt_wss_client client, int timeout_ms)
821
nd_log(NDLS_DAEMON, NDLP_ERR, "poll error \"%s\"", strerror(errno));
822
return -2;
823
}
824
+ worker_is_busy(WORKER_ACLK_POLL_OK);
825
826
#ifdef MQTT_WSS_CPUSTATS
827
t1 = mqtt_wss_now_usec();
@@ -817,6 +834,7 @@ int mqtt_wss_service(mqtt_wss_client client, int timeout_ms)
834
// MQTT keep alives
835
mqtt_ng_ping(client->mqtt);
836
ping_timeout = now + PING_TIMEOUT;
837
+ worker_is_busy(WORKER_ACLK_SENT_PING);
838
} else {
839
if (ping_timeout && ping_timeout < now) {
840
disconnect_req = ACLK_PING_TIMEOUT;
@@ -836,6 +854,8 @@ int mqtt_wss_service(mqtt_wss_client client, int timeout_ms)
854
client->poll_fds[POLLFD_SOCKET].events = 0;
855
856
if ((ptr = rbuf_get_linear_insert_range(client->ws_client->buf_read, &size))) {
857
+ worker_is_busy(WORKER_ACLK_RX);
858
+
859
if((ret = SSL_read(client->ssl, ptr, size)) > 0) {
860
spinlock_lock(&client->stat_lock);
861
client->stats.bytes_rx += ret;
@@ -847,6 +867,7 @@ int mqtt_wss_service(mqtt_wss_client client, int timeout_ms)
867
set_socket_pollfds(client, ret);
868
if (ret != SSL_ERROR_WANT_READ &&
869
ret != SSL_ERROR_WANT_WRITE) {
870
+ worker_is_busy(WORKER_ACLK_RX_ERROR);
871
nd_log(NDLS_DAEMON, NDLP_ERR, "SSL_read error: %d %s", ret, util_openssl_ret_err(ret));
872
if (ret == SSL_ERROR_SYSCALL)
873
nd_log(NDLS_DAEMON, NDLP_ERR, "SSL_read SYSCALL errno: %d %s", errnobkp, strerror(errnobkp));
@@ -882,9 +903,11 @@ int mqtt_wss_service(mqtt_wss_client client, int timeout_ms)
903
#endif
904
905
// process MQTT stuff
885
- if(client->ws_client->state == WS_ESTABLISHED)
906
+ if(client->ws_client->state == WS_ESTABLISHED) {
907
+ worker_is_busy(WORKER_ACLK_HANDLE_MQTT_INTERNAL);
908
if (handle_mqtt_internal(client))
909
return MQTT_WSS_ERR_PROTO_MQTT;
910
+ }
911
912
if (client->mqtt_didnt_finish_write) {
913
client->mqtt_didnt_finish_write = 0;
@@ -897,6 +920,8 @@ int mqtt_wss_service(mqtt_wss_client client, int timeout_ms)
920
#endif
921
922
if ((ptr = rbuf_get_linear_read_range(client->ws_client->buf_write, &size))) {
923
+ worker_is_busy(WORKER_ACLK_TX);
924
+
925
if ((ret = SSL_write(client->ssl, ptr, size)) > 0) {
926
spinlock_lock(&client->stat_lock);
927
client->stats.bytes_tx += ret;
@@ -908,6 +933,7 @@ int mqtt_wss_service(mqtt_wss_client client, int timeout_ms)
933
set_socket_pollfds(client, ret);
934
if (ret != SSL_ERROR_WANT_READ &&
935
ret != SSL_ERROR_WANT_WRITE) {
936
+ worker_is_busy(WORKER_ACLK_TX_ERROR);
937
nd_log(NDLS_DAEMON, NDLP_ERR, "SSL_write error: %d %s", ret, util_openssl_ret_err(ret));
938
if (ret == SSL_ERROR_SYSCALL)
939
nd_log(NDLS_DAEMON, NDLP_ERR, "SSL_write SYSCALL errno: %d %s", errnobkp, strerror(errnobkp));
src/aclk/mqtt_websockets/mqtt_wss_client.h
+1
-2
@@ -5,7 +5,6 @@
5
6
#include "common_public.h"
7
8
-
8
#define MQTT_WSS_OK 0 // All OK call me at your earliest convinience
9
#define MQTT_WSS_OK_TO 1 // All OK, poll timeout you requested when calling mqtt_wss_service expired
10
//you might want to know if timeout
@@ -58,7 +57,7 @@ int mqtt_wss_connect(
57
int ssl_flags,
58
const struct mqtt_wss_proxy *proxy,
59
bool *fallback_ipv4);
61
-int mqtt_wss_service(mqtt_wss_client client, int timeout_ms);
60
+int mqtt_wss_service(mqtt_wss_client client, int t_ms);
61
void mqtt_wss_disconnect(mqtt_wss_client client, int timeout_ms);
62
63
// we redefine this instead of using MQTT-C flags as in future
src/aclk/mqtt_websockets/ws_client.c
+7
@@ -4,6 +4,7 @@
4
5
#include "ws_client.h"
6
#include "common_internal.h"
7
+#include "aclk_mqtt_workers.h"
8
9
const char *websocket_upgrage_hdr = "GET /mqtt HTTP/1.1\x0D\x0A"
10
"Host: %s\x0D\x0A"
@@ -623,10 +624,12 @@ int ws_client_process(ws_client *client)
624
int ret;
625
switch(client->state) {
626
case WS_RAW:
627
+ worker_is_busy(WORKER_ACLK_PROCESS_RAW);
628
if (ws_client_start_handshake(client))
629
return WS_CLIENT_INTERNAL_ERROR;
630
return WS_CLIENT_NEED_MORE_BYTES;
631
case WS_HANDSHAKE:
632
+ worker_is_busy(WORKER_ACLK_PROCESS_HANDSHAKE);
633
do {
634
ret = ws_client_parse_handshake_resp(client);
635
if (ret == WS_CLIENT_PROTOCOL_ERROR)
@@ -636,6 +639,7 @@ int ws_client_process(ws_client *client)
639
} while (!ret);
640
break;
641
case WS_ESTABLISHED:
642
+ worker_is_busy(WORKER_ACLK_PROCESS_ESTABLISHED);
643
do {
644
ret = ws_client_process_rx_ws(client);
645
switch(ret) {
@@ -655,12 +659,15 @@ int ws_client_process(ws_client *client)
659
} while (!ret || ret == WS_CLIENT_PARSING_DONE);
660
break;
661
case WS_ERROR:
662
+ worker_is_busy(WORKER_ACLK_PROCESS_ERROR);
663
nd_log(NDLS_DAEMON, NDLP_ERR, "ws_client is in error state. Restart the connection!");
664
return WS_CLIENT_PROTOCOL_ERROR;
665
case WS_CONN_CLOSED_GRACEFUL:
666
+ worker_is_busy(WORKER_ACLK_PROCESS_CLOSED_GRACEFULLY);
667
nd_log(NDLS_DAEMON, NDLP_ERR, "Connection has been gracefully closed. Calling this is useless (and probably bug) until you reconnect again.");
668
return WS_CLIENT_CONNECTION_CLOSED;
669
default:
670
+ worker_is_busy(WORKER_ACLK_PROCESS_UNKNOWN);
671
nd_log(NDLS_DAEMON, NDLP_CRIT, "Unknown connection state! Probably memory corruption.");
672
return WS_CLIENT_INTERNAL_ERROR;
673
}
src/daemon/pulse/pulse-workers.c
+1
@@ -125,6 +125,7 @@ static struct worker_utilization all_workers_utilization[] = {
125
{ .name = "DBENGINE", .family = "workers dbengine instances", .priority = 1000000 },
126
{ .name = "LIBUV", .family = "workers libuv threadpool", .priority = 1000000 },
127
{ .name = "WEB", .family = "workers web server", .priority = 1000000 },
128
+ { .name = "ACLK", .family = "workers aclk", .priority = 1000000 },
129
{ .name = "ACLKSYNC", .family = "workers aclk sync", .priority = 1000000 },
130
{ .name = "METASYNC", .family = "workers metadata sync", .priority = 1000000 },
131
{ .name = "PLUGINSD", .family = "workers plugins.d", .priority = 1000000 },