feat(emqx_bridge_iotdb): handle bad message format gracefully

This commit is contained in:
Stefan Strigler 2023-05-26 13:52:16 +02:00
parent 0f080cda66
commit 6f54220a51
1 changed files with 73 additions and 45 deletions

View File

@ -110,15 +110,19 @@ on_query(InstanceId, {send_message, Message}, State) ->
send_message => Message, send_message => Message,
state => emqx_utils:redact(State) state => emqx_utils:redact(State)
}), }),
IoTDBPayload = make_iotdb_insert_request(Message, State), case make_iotdb_insert_request(Message, State) of
{ok, IoTDBPayload} ->
handle_response( handle_response(
emqx_connector_http:on_query( emqx_connector_http:on_query(
InstanceId, {send_message, IoTDBPayload}, State InstanceId, {send_message, IoTDBPayload}, State
) )
). );
Error ->
Error
end.
-spec on_query_async(manager_id(), {send_message, map()}, {function(), [term()]}, state()) -> -spec on_query_async(manager_id(), {send_message, map()}, {function(), [term()]}, state()) ->
{ok, pid()}. {ok, pid()} | {error, empty_request}.
on_query_async(InstanceId, {send_message, Message}, ReplyFunAndArgs0, State) -> on_query_async(InstanceId, {send_message, Message}, ReplyFunAndArgs0, State) ->
?SLOG(debug, #{ ?SLOG(debug, #{
msg => "iotdb_bridge_on_query_async_called", msg => "iotdb_bridge_on_query_async_called",
@ -126,7 +130,8 @@ on_query_async(InstanceId, {send_message, Message}, ReplyFunAndArgs0, State) ->
send_message => Message, send_message => Message,
state => emqx_utils:redact(State) state => emqx_utils:redact(State)
}), }),
IoTDBPayload = make_iotdb_insert_request(Message, State), case make_iotdb_insert_request(Message, State) of
{ok, IoTDBPayload} ->
ReplyFunAndArgs = ReplyFunAndArgs =
{ {
fun(Result) -> fun(Result) ->
@ -137,7 +142,10 @@ on_query_async(InstanceId, {send_message, Message}, ReplyFunAndArgs0, State) ->
}, },
emqx_connector_http:on_query_async( emqx_connector_http:on_query_async(
InstanceId, {send_message, IoTDBPayload}, ReplyFunAndArgs, State InstanceId, {send_message, IoTDBPayload}, ReplyFunAndArgs, State
). );
Error ->
Error
end.
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
%% Internal Functions %% Internal Functions
@ -160,13 +168,22 @@ make_parsed_payload(
<<"value">> => Value <<"value">> => Value
}. }.
preproc_data_list(DataList) ->
lists:foldl(
fun preproc_data/2,
[],
DataList
).
preproc_data( preproc_data(
#{ #{
<<"measurement">> := Measurement, <<"measurement">> := Measurement,
<<"data_type">> := DataType, <<"data_type">> := DataType,
<<"value">> := Value <<"value">> := Value
} = Data } = Data,
Acc
) -> ) ->
[
#{ #{
timestamp => emqx_plugin_libs_rule:preproc_tmpl( timestamp => emqx_plugin_libs_rule:preproc_tmpl(
maps:get(<<"timestamp">>, Data, <<"now">>) maps:get(<<"timestamp">>, Data, <<"now">>)
@ -174,13 +191,19 @@ preproc_data(
measurement => emqx_plugin_libs_rule:preproc_tmpl(Measurement), measurement => emqx_plugin_libs_rule:preproc_tmpl(Measurement),
data_type => DataType, data_type => DataType,
value => emqx_plugin_libs_rule:preproc_tmpl(Value) value => emqx_plugin_libs_rule:preproc_tmpl(Value)
}. }
| Acc
preproc_data_list(DataList) -> ];
lists:map( preproc_data(_NoMatch, Acc) ->
fun preproc_data/1, ?SLOG(
DataList warning,
). #{
msg => "iotdb_bridge_preproc_data_failed",
required_fields => ['measurement', 'data_type', 'value'],
received => _NoMatch
}
),
Acc.
proc_data(PreProcessedData, Msg) -> proc_data(PreProcessedData, Msg) ->
NowNS = erlang:system_time(nanosecond), NowNS = erlang:system_time(nanosecond),
@ -282,18 +305,23 @@ make_iotdb_insert_request(MessageUnparsedPayload, State) ->
DeviceId = device_id(Message, State), DeviceId = device_id(Message, State),
IotDBVsn = maps:get(iotdb_version, State, ?VSN_1_1_X), IotDBVsn = maps:get(iotdb_version, State, ?VSN_1_1_X),
Payload = make_list(maps:get(payload, Message)), Payload = make_list(maps:get(payload, Message)),
PreProcessedData = preproc_data_list(Payload), case preproc_data_list(Payload) of
[] ->
{error, invalid_data};
PreProcessedData ->
DataList = proc_data(PreProcessedData, Message), DataList = proc_data(PreProcessedData, Message),
InitAcc = #{timestamps => [], measurements => [], dtypes => [], values => []}, InitAcc = #{timestamps => [], measurements => [], dtypes => [], values => []},
Rows = replace_dtypes(aggregate_rows(DataList, InitAcc), IotDBVsn), Rows = replace_dtypes(aggregate_rows(DataList, InitAcc), IotDBVsn),
{ok,
maps:merge(Rows, #{ maps:merge(Rows, #{
iotdb_field_key(is_aligned, IotDBVsn) => IsAligned, iotdb_field_key(is_aligned, IotDBVsn) => IsAligned,
iotdb_field_key(device_id, IotDBVsn) => DeviceId iotdb_field_key(device_id, IotDBVsn) => DeviceId
}). })}
end.
replace_dtypes(Rows, IotDBVsn) -> replace_dtypes(Rows0, IotDBVsn) ->
{Types, Map} = maps:take(dtypes, Rows), {Types, Rows} = maps:take(dtypes, Rows0),
Map#{iotdb_field_key(data_types, IotDBVsn) => Types}. Rows#{iotdb_field_key(data_types, IotDBVsn) => Types}.
aggregate_rows(DataList, InitAcc) -> aggregate_rows(DataList, InitAcc) ->
lists:foldr( lists:foldr(