feat(respool): switch to `emqx_resource_pool`

Which was previously known as `emqx_plugin_libs_pool`. This is part
of the effort to get rid of `emqx_plugin_libs` application.
This commit is contained in:
Andrew Mayorov 2023-04-12 16:37:51 +03:00
parent 4240720753
commit 21e19a33ce
No known key found for this signature in database
GPG Key ID: 2837C62ACFBFED5D
22 changed files with 312 additions and 372 deletions

View File

@ -35,18 +35,17 @@
callback_mode() -> always_sync. callback_mode() -> always_sync.
on_start(InstId, Opts) -> on_start(InstId, Opts) ->
PoolName = emqx_plugin_libs_pool:pool_name(InstId),
PoolOpts = [ PoolOpts = [
{pool_size, maps:get(pool_size, Opts, ?DEFAULT_POOL_SIZE)}, {pool_size, maps:get(pool_size, Opts, ?DEFAULT_POOL_SIZE)},
{connector_opts, Opts} {connector_opts, Opts}
], ],
case emqx_plugin_libs_pool:start_pool(PoolName, ?MODULE, PoolOpts) of case emqx_resource_pool:start(InstId, ?MODULE, PoolOpts) of
ok -> {ok, #{pool_name => PoolName}}; ok -> {ok, #{pool_name => InstId}};
{error, Reason} -> {error, Reason} {error, Reason} -> {error, Reason}
end. end.
on_stop(_InstId, #{pool_name := PoolName}) -> on_stop(_InstId, #{pool_name := PoolName}) ->
emqx_plugin_libs_pool:stop_pool(PoolName). emqx_resource_pool:stop(PoolName).
on_query(InstId, get_jwks, #{pool_name := PoolName}) -> on_query(InstId, get_jwks, #{pool_name := PoolName}) ->
Result = ecpool:pick_and_do(PoolName, {emqx_authn_jwks_client, get_jwks, []}, no_handover), Result = ecpool:pick_and_do(PoolName, {emqx_authn_jwks_client, get_jwks, []}, no_handover),
@ -72,16 +71,15 @@ on_query(_InstId, {update, Opts}, #{pool_name := PoolName}) ->
ok. ok.
on_get_status(_InstId, #{pool_name := PoolName}) -> on_get_status(_InstId, #{pool_name := PoolName}) ->
Func = case emqx_resource_pool:health_check_workers(PoolName, fun health_check/1) of
fun(Conn) -> true -> connected;
false -> disconnected
end.
health_check(Conn) ->
case emqx_authn_jwks_client:get_jwks(Conn) of case emqx_authn_jwks_client:get_jwks(Conn) of
{ok, _} -> true; {ok, _} -> true;
_ -> false _ -> false
end
end,
case emqx_plugin_libs_pool:health_check_ecpool_workers(PoolName, Func) of
true -> connected;
false -> disconnected
end. end.
connect(Opts) -> connect(Opts) ->

View File

@ -231,9 +231,8 @@ on_start(
{transport_opts, NTransportOpts}, {transport_opts, NTransportOpts},
{enable_pipelining, maps:get(enable_pipelining, Config, ?DEFAULT_PIPELINE_SIZE)} {enable_pipelining, maps:get(enable_pipelining, Config, ?DEFAULT_PIPELINE_SIZE)}
], ],
PoolName = emqx_plugin_libs_pool:pool_name(InstId),
State = #{ State = #{
pool_name => PoolName, pool_name => InstId,
pool_type => PoolType, pool_type => PoolType,
host => Host, host => Host,
port => Port, port => Port,
@ -241,7 +240,7 @@ on_start(
base_path => BasePath, base_path => BasePath,
request => preprocess_request(maps:get(request, Config, undefined)) request => preprocess_request(maps:get(request, Config, undefined))
}, },
case ehttpc_sup:start_pool(PoolName, PoolOpts) of case ehttpc_sup:start_pool(InstId, PoolOpts) of
{ok, _} -> {ok, State}; {ok, _} -> {ok, State};
{error, {already_started, _}} -> {ok, State}; {error, {already_started, _}} -> {ok, State};
{error, Reason} -> {error, Reason} {error, Reason} -> {error, Reason}

View File

@ -87,20 +87,19 @@ on_start(
{pool_size, PoolSize}, {pool_size, PoolSize},
{auto_reconnect, ?AUTO_RECONNECT_INTERVAL} {auto_reconnect, ?AUTO_RECONNECT_INTERVAL}
], ],
PoolName = emqx_plugin_libs_pool:pool_name(InstId), case emqx_resource_pool:start(InstId, ?MODULE, Opts ++ SslOpts) of
case emqx_plugin_libs_pool:start_pool(PoolName, ?MODULE, Opts ++ SslOpts) of ok -> {ok, #{pool_name => InstId}};
ok -> {ok, #{poolname => PoolName}};
{error, Reason} -> {error, Reason} {error, Reason} -> {error, Reason}
end. end.
on_stop(InstId, #{poolname := PoolName}) -> on_stop(InstId, #{pool_name := PoolName}) ->
?SLOG(info, #{ ?SLOG(info, #{
msg => "stopping_ldap_connector", msg => "stopping_ldap_connector",
connector => InstId connector => InstId
}), }),
emqx_plugin_libs_pool:stop_pool(PoolName). emqx_resource_pool:stop(PoolName).
on_query(InstId, {search, Base, Filter, Attributes}, #{poolname := PoolName} = State) -> on_query(InstId, {search, Base, Filter, Attributes}, #{pool_name := PoolName} = State) ->
Request = {Base, Filter, Attributes}, Request = {Base, Filter, Attributes},
?TRACE( ?TRACE(
"QUERY", "QUERY",

View File

@ -182,12 +182,11 @@ on_start(
{options, init_topology_options(maps:to_list(Topology), [])}, {options, init_topology_options(maps:to_list(Topology), [])},
{worker_options, init_worker_options(maps:to_list(NConfig), SslOpts)} {worker_options, init_worker_options(maps:to_list(NConfig), SslOpts)}
], ],
PoolName = emqx_plugin_libs_pool:pool_name(InstId),
Collection = maps:get(collection, Config, <<"mqtt">>), Collection = maps:get(collection, Config, <<"mqtt">>),
case emqx_plugin_libs_pool:start_pool(PoolName, ?MODULE, Opts) of case emqx_resource_pool:start(InstId, ?MODULE, Opts) of
ok -> ok ->
{ok, #{ {ok, #{
poolname => PoolName, pool_name => InstId,
type => Type, type => Type,
collection => Collection collection => Collection
}}; }};
@ -195,17 +194,17 @@ on_start(
{error, Reason} {error, Reason}
end. end.
on_stop(InstId, #{poolname := PoolName}) -> on_stop(InstId, #{pool_name := PoolName}) ->
?SLOG(info, #{ ?SLOG(info, #{
msg => "stopping_mongodb_connector", msg => "stopping_mongodb_connector",
connector => InstId connector => InstId
}), }),
emqx_plugin_libs_pool:stop_pool(PoolName). emqx_resource_pool:stop(PoolName).
on_query( on_query(
InstId, InstId,
{send_message, Document}, {send_message, Document},
#{poolname := PoolName, collection := Collection} = State #{pool_name := PoolName, collection := Collection} = State
) -> ) ->
Request = {insert, Collection, Document}, Request = {insert, Collection, Document},
?TRACE( ?TRACE(
@ -234,7 +233,7 @@ on_query(
on_query( on_query(
InstId, InstId,
{Action, Collection, Filter, Projector}, {Action, Collection, Filter, Projector},
#{poolname := PoolName} = State #{pool_name := PoolName} = State
) -> ) ->
Request = {Action, Collection, Filter, Projector}, Request = {Action, Collection, Filter, Projector},
?TRACE( ?TRACE(
@ -263,8 +262,7 @@ on_query(
{ok, Result} {ok, Result}
end. end.
-dialyzer({nowarn_function, [on_get_status/2]}). on_get_status(InstId, #{pool_name := PoolName}) ->
on_get_status(InstId, #{poolname := PoolName} = _State) ->
case health_check(PoolName) of case health_check(PoolName) of
true -> true ->
?tp(debug, emqx_connector_mongo_health_check, #{ ?tp(debug, emqx_connector_mongo_health_check, #{
@ -281,8 +279,10 @@ on_get_status(InstId, #{poolname := PoolName} = _State) ->
end. end.
health_check(PoolName) -> health_check(PoolName) ->
emqx_plugin_libs_pool:health_check_ecpool_workers( emqx_resource_pool:health_check_workers(
PoolName, fun ?MODULE:check_worker_health/1, ?HEALTH_CHECK_TIMEOUT + timer:seconds(1) PoolName,
fun ?MODULE:check_worker_health/1,
?HEALTH_CHECK_TIMEOUT + timer:seconds(1)
). ).
%% =================================================================== %% ===================================================================

View File

@ -51,7 +51,7 @@
-type sqls() :: #{atom() => binary()}. -type sqls() :: #{atom() => binary()}.
-type state() :: -type state() ::
#{ #{
poolname := atom(), pool_name := binary(),
prepare_statement := prepares(), prepare_statement := prepares(),
params_tokens := params_tokens(), params_tokens := params_tokens(),
batch_inserts := sqls(), batch_inserts := sqls(),
@ -123,13 +123,10 @@ on_start(
{pool_size, PoolSize} {pool_size, PoolSize}
] ]
), ),
State = parse_prepare_sql(Config),
PoolName = emqx_plugin_libs_pool:pool_name(InstId), case emqx_resource_pool:start(InstId, ?MODULE, Options ++ SslOpts) of
Prepares = parse_prepare_sql(Config),
State = maps:merge(#{poolname => PoolName}, Prepares),
case emqx_plugin_libs_pool:start_pool(PoolName, ?MODULE, Options ++ SslOpts) of
ok -> ok ->
{ok, init_prepare(State)}; {ok, init_prepare(State#{pool_name => InstId})};
{error, Reason} -> {error, Reason} ->
?tp( ?tp(
mysql_connector_start_failed, mysql_connector_start_failed,
@ -143,12 +140,12 @@ maybe_add_password_opt(undefined, Options) ->
maybe_add_password_opt(Password, Options) -> maybe_add_password_opt(Password, Options) ->
[{password, Password} | Options]. [{password, Password} | Options].
on_stop(InstId, #{poolname := PoolName}) -> on_stop(InstId, #{pool_name := PoolName}) ->
?SLOG(info, #{ ?SLOG(info, #{
msg => "stopping_mysql_connector", msg => "stopping_mysql_connector",
connector => InstId connector => InstId
}), }),
emqx_plugin_libs_pool:stop_pool(PoolName). emqx_resource_pool:stop(PoolName).
on_query(InstId, {TypeOrKey, SQLOrKey}, State) -> on_query(InstId, {TypeOrKey, SQLOrKey}, State) ->
on_query(InstId, {TypeOrKey, SQLOrKey, [], default_timeout}, State); on_query(InstId, {TypeOrKey, SQLOrKey, [], default_timeout}, State);
@ -157,7 +154,7 @@ on_query(InstId, {TypeOrKey, SQLOrKey, Params}, State) ->
on_query( on_query(
InstId, InstId,
{TypeOrKey, SQLOrKey, Params, Timeout}, {TypeOrKey, SQLOrKey, Params, Timeout},
#{poolname := PoolName, prepare_statement := Prepares} = State #{pool_name := PoolName, prepare_statement := Prepares} = State
) -> ) ->
MySqlFunction = mysql_function(TypeOrKey), MySqlFunction = mysql_function(TypeOrKey),
{SQLOrKey2, Data} = proc_sql_params(TypeOrKey, SQLOrKey, Params, State), {SQLOrKey2, Data} = proc_sql_params(TypeOrKey, SQLOrKey, Params, State),
@ -216,8 +213,8 @@ mysql_function(prepared_query) ->
mysql_function(_) -> mysql_function(_) ->
mysql_function(prepared_query). mysql_function(prepared_query).
on_get_status(_InstId, #{poolname := Pool} = State) -> on_get_status(_InstId, #{pool_name := PoolName} = State) ->
case emqx_plugin_libs_pool:health_check_ecpool_workers(Pool, fun ?MODULE:do_get_status/1) of case emqx_resource_pool:health_check_workers(PoolName, fun ?MODULE:do_get_status/1) of
true -> true ->
case do_check_prepares(State) of case do_check_prepares(State) of
ok -> ok ->
@ -238,7 +235,7 @@ do_get_status(Conn) ->
do_check_prepares(#{prepare_statement := Prepares}) when is_map(Prepares) -> do_check_prepares(#{prepare_statement := Prepares}) when is_map(Prepares) ->
ok; ok;
do_check_prepares(State = #{poolname := PoolName, prepare_statement := {error, Prepares}}) -> do_check_prepares(State = #{pool_name := PoolName, prepare_statement := {error, Prepares}}) ->
%% retry to prepare %% retry to prepare
case prepare_sql(Prepares, PoolName) of case prepare_sql(Prepares, PoolName) of
ok -> ok ->
@ -253,7 +250,7 @@ do_check_prepares(State = #{poolname := PoolName, prepare_statement := {error, P
connect(Options) -> connect(Options) ->
mysql:start_link(Options). mysql:start_link(Options).
init_prepare(State = #{prepare_statement := Prepares, poolname := PoolName}) -> init_prepare(State = #{prepare_statement := Prepares, pool_name := PoolName}) ->
case maps:size(Prepares) of case maps:size(Prepares) of
0 -> 0 ->
State; State;
@ -409,7 +406,7 @@ on_sql_query(
SQLOrKey, SQLOrKey,
Params, Params,
Timeout, Timeout,
#{poolname := PoolName} = State #{pool_name := PoolName} = State
) -> ) ->
LogMeta = #{connector => InstId, sql => SQLOrKey, state => State}, LogMeta = #{connector => InstId, sql => SQLOrKey, state => State},
?TRACE("QUERY", "mysql_connector_received", LogMeta), ?TRACE("QUERY", "mysql_connector_received", LogMeta),

View File

@ -56,7 +56,7 @@
-type state() :: -type state() ::
#{ #{
poolname := atom(), pool_name := binary(),
prepare_sql := prepares(), prepare_sql := prepares(),
params_tokens := params_tokens(), params_tokens := params_tokens(),
prepare_statement := epgsql:statement() prepare_statement := epgsql:statement()
@ -120,13 +120,10 @@ on_start(
{auto_reconnect, ?AUTO_RECONNECT_INTERVAL}, {auto_reconnect, ?AUTO_RECONNECT_INTERVAL},
{pool_size, PoolSize} {pool_size, PoolSize}
], ],
PoolName = emqx_plugin_libs_pool:pool_name(InstId), State = parse_prepare_sql(Config),
Prepares = parse_prepare_sql(Config), case emqx_resource_pool:start(InstId, ?MODULE, Options ++ SslOpts) of
InitState = #{poolname => PoolName, prepare_statement => #{}},
State = maps:merge(InitState, Prepares),
case emqx_plugin_libs_pool:start_pool(PoolName, ?MODULE, Options ++ SslOpts) of
ok -> ok ->
{ok, init_prepare(State)}; {ok, init_prepare(State#{pool_name => InstId, prepare_statement => #{}})};
{error, Reason} -> {error, Reason} ->
?tp( ?tp(
pgsql_connector_start_failed, pgsql_connector_start_failed,
@ -135,19 +132,19 @@ on_start(
{error, Reason} {error, Reason}
end. end.
on_stop(InstId, #{poolname := PoolName}) -> on_stop(InstId, #{pool_name := PoolName}) ->
?SLOG(info, #{ ?SLOG(info, #{
msg => "stopping postgresql connector", msg => "stopping postgresql connector",
connector => InstId connector => InstId
}), }),
emqx_plugin_libs_pool:stop_pool(PoolName). emqx_resource_pool:stop(PoolName).
on_query(InstId, {TypeOrKey, NameOrSQL}, #{poolname := _PoolName} = State) -> on_query(InstId, {TypeOrKey, NameOrSQL}, State) ->
on_query(InstId, {TypeOrKey, NameOrSQL, []}, State); on_query(InstId, {TypeOrKey, NameOrSQL, []}, State);
on_query( on_query(
InstId, InstId,
{TypeOrKey, NameOrSQL, Params}, {TypeOrKey, NameOrSQL, Params},
#{poolname := PoolName} = State #{pool_name := PoolName} = State
) -> ) ->
?SLOG(debug, #{ ?SLOG(debug, #{
msg => "postgresql connector received sql query", msg => "postgresql connector received sql query",
@ -174,7 +171,7 @@ pgsql_query_type(_) ->
on_batch_query( on_batch_query(
InstId, InstId,
BatchReq, BatchReq,
#{poolname := PoolName, params_tokens := Tokens, prepare_statement := Sts} = State #{pool_name := PoolName, params_tokens := Tokens, prepare_statement := Sts} = State
) -> ) ->
case BatchReq of case BatchReq of
[{Key, _} = Request | _] -> [{Key, _} = Request | _] ->
@ -258,8 +255,8 @@ on_sql_query(InstId, PoolName, Type, NameOrSQL, Data) ->
{error, {unrecoverable_error, invalid_request}} {error, {unrecoverable_error, invalid_request}}
end. end.
on_get_status(_InstId, #{poolname := Pool} = State) -> on_get_status(_InstId, #{pool_name := PoolName} = State) ->
case emqx_plugin_libs_pool:health_check_ecpool_workers(Pool, fun ?MODULE:do_get_status/1) of case emqx_resource_pool:health_check_workers(PoolName, fun ?MODULE:do_get_status/1) of
true -> true ->
case do_check_prepares(State) of case do_check_prepares(State) of
ok -> ok ->
@ -280,7 +277,7 @@ do_get_status(Conn) ->
do_check_prepares(#{prepare_sql := Prepares}) when is_map(Prepares) -> do_check_prepares(#{prepare_sql := Prepares}) when is_map(Prepares) ->
ok; ok;
do_check_prepares(State = #{poolname := PoolName, prepare_sql := {error, Prepares}}) -> do_check_prepares(State = #{pool_name := PoolName, prepare_sql := {error, Prepares}}) ->
%% retry to prepare %% retry to prepare
case prepare_sql(Prepares, PoolName) of case prepare_sql(Prepares, PoolName) of
{ok, Sts} -> {ok, Sts} ->
@ -358,7 +355,7 @@ parse_prepare_sql([], Prepares, Tokens) ->
params_tokens => Tokens params_tokens => Tokens
}. }.
init_prepare(State = #{prepare_sql := Prepares, poolname := PoolName}) -> init_prepare(State = #{prepare_sql := Prepares, pool_name := PoolName}) ->
case maps:size(Prepares) of case maps:size(Prepares) of
0 -> 0 ->
State; State;
@ -389,17 +386,17 @@ prepare_sql(Prepares, PoolName) ->
end. end.
do_prepare_sql(Prepares, PoolName) -> do_prepare_sql(Prepares, PoolName) ->
do_prepare_sql(ecpool:workers(PoolName), Prepares, PoolName, #{}). do_prepare_sql(ecpool:workers(PoolName), Prepares, #{}).
do_prepare_sql([{_Name, Worker} | T], Prepares, PoolName, _LastSts) -> do_prepare_sql([{_Name, Worker} | T], Prepares, _LastSts) ->
{ok, Conn} = ecpool_worker:client(Worker), {ok, Conn} = ecpool_worker:client(Worker),
case prepare_sql_to_conn(Conn, Prepares) of case prepare_sql_to_conn(Conn, Prepares) of
{ok, Sts} -> {ok, Sts} ->
do_prepare_sql(T, Prepares, PoolName, Sts); do_prepare_sql(T, Prepares, Sts);
Error -> Error ->
Error Error
end; end;
do_prepare_sql([], _Prepares, _PoolName, LastSts) -> do_prepare_sql([], _Prepares, LastSts) ->
{ok, LastSts}. {ok, LastSts}.
prepare_sql_to_conn(Conn, Prepares) -> prepare_sql_to_conn(Conn, Prepares) ->

View File

@ -153,11 +153,10 @@ on_start(
false -> false ->
[{ssl, false}] [{ssl, false}]
end ++ [{sentinel, maps:get(sentinel, Config, undefined)}], end ++ [{sentinel, maps:get(sentinel, Config, undefined)}],
PoolName = InstId, State = #{pool_name => InstId, type => Type},
State = #{poolname => PoolName, type => Type},
case Type of case Type of
cluster -> cluster ->
case eredis_cluster:start_pool(PoolName, Opts ++ [{options, Options}]) of case eredis_cluster:start_pool(InstId, Opts ++ [{options, Options}]) of
{ok, _} -> {ok, _} ->
{ok, State}; {ok, State};
{ok, _, _} -> {ok, _, _} ->
@ -166,22 +165,20 @@ on_start(
{error, Reason} {error, Reason}
end; end;
_ -> _ ->
case case emqx_resource_pool:start(InstId, ?MODULE, Opts ++ [{options, Options}]) of
emqx_plugin_libs_pool:start_pool(PoolName, ?MODULE, Opts ++ [{options, Options}])
of
ok -> {ok, State}; ok -> {ok, State};
{error, Reason} -> {error, Reason} {error, Reason} -> {error, Reason}
end end
end. end.
on_stop(InstId, #{poolname := PoolName, type := Type}) -> on_stop(InstId, #{pool_name := PoolName, type := Type}) ->
?SLOG(info, #{ ?SLOG(info, #{
msg => "stopping_redis_connector", msg => "stopping_redis_connector",
connector => InstId connector => InstId
}), }),
case Type of case Type of
cluster -> eredis_cluster:stop_pool(PoolName); cluster -> eredis_cluster:stop_pool(PoolName);
_ -> emqx_plugin_libs_pool:stop_pool(PoolName) _ -> emqx_resource_pool:stop(PoolName)
end. end.
on_query(InstId, {cmd, _} = Query, State) -> on_query(InstId, {cmd, _} = Query, State) ->
@ -189,7 +186,7 @@ on_query(InstId, {cmd, _} = Query, State) ->
on_query(InstId, {cmds, _} = Query, State) -> on_query(InstId, {cmds, _} = Query, State) ->
do_query(InstId, Query, State). do_query(InstId, Query, State).
do_query(InstId, Query, #{poolname := PoolName, type := Type} = State) -> do_query(InstId, Query, #{pool_name := PoolName, type := Type} = State) ->
?TRACE( ?TRACE(
"QUERY", "QUERY",
"redis_connector_received", "redis_connector_received",
@ -227,7 +224,7 @@ is_unrecoverable_error({error, invalid_cluster_command}) ->
is_unrecoverable_error(_) -> is_unrecoverable_error(_) ->
false. false.
on_get_status(_InstId, #{type := cluster, poolname := PoolName}) -> on_get_status(_InstId, #{type := cluster, pool_name := PoolName}) ->
case eredis_cluster:pool_exists(PoolName) of case eredis_cluster:pool_exists(PoolName) of
true -> true ->
Health = eredis_cluster:ping_all(PoolName), Health = eredis_cluster:ping_all(PoolName),
@ -235,8 +232,8 @@ on_get_status(_InstId, #{type := cluster, poolname := PoolName}) ->
false -> false ->
disconnected disconnected
end; end;
on_get_status(_InstId, #{poolname := Pool}) -> on_get_status(_InstId, #{pool_name := PoolName}) ->
Health = emqx_plugin_libs_pool:health_check_ecpool_workers(Pool, fun ?MODULE:do_get_status/1), Health = emqx_resource_pool:health_check_workers(PoolName, fun ?MODULE:do_get_status/1),
status_result(Health). status_result(Health).
do_get_status(Conn) -> do_get_status(Conn) ->

View File

@ -64,15 +64,15 @@ t_lifecycle(_Config) ->
mongo_config() mongo_config()
). ).
perform_lifecycle_check(PoolName, InitialConfig) -> perform_lifecycle_check(ResourceId, InitialConfig) ->
{ok, #{config := CheckedConfig}} = {ok, #{config := CheckedConfig}} =
emqx_resource:check_config(?MONGO_RESOURCE_MOD, InitialConfig), emqx_resource:check_config(?MONGO_RESOURCE_MOD, InitialConfig),
{ok, #{ {ok, #{
state := #{poolname := ReturnedPoolName} = State, state := #{pool_name := PoolName} = State,
status := InitialStatus status := InitialStatus
}} = }} =
emqx_resource:create_local( emqx_resource:create_local(
PoolName, ResourceId,
?CONNECTOR_RESOURCE_GROUP, ?CONNECTOR_RESOURCE_GROUP,
?MONGO_RESOURCE_MOD, ?MONGO_RESOURCE_MOD,
CheckedConfig, CheckedConfig,
@ -84,39 +84,39 @@ perform_lifecycle_check(PoolName, InitialConfig) ->
state := State, state := State,
status := InitialStatus status := InitialStatus
}} = }} =
emqx_resource:get_instance(PoolName), emqx_resource:get_instance(ResourceId),
?assertEqual({ok, connected}, emqx_resource:health_check(PoolName)), ?assertEqual({ok, connected}, emqx_resource:health_check(ResourceId)),
% % Perform query as further check that the resource is working as expected % % Perform query as further check that the resource is working as expected
?assertMatch({ok, []}, emqx_resource:query(PoolName, test_query_find())), ?assertMatch({ok, []}, emqx_resource:query(ResourceId, test_query_find())),
?assertMatch({ok, undefined}, emqx_resource:query(PoolName, test_query_find_one())), ?assertMatch({ok, undefined}, emqx_resource:query(ResourceId, test_query_find_one())),
?assertEqual(ok, emqx_resource:stop(PoolName)), ?assertEqual(ok, emqx_resource:stop(ResourceId)),
% Resource will be listed still, but state will be changed and healthcheck will fail % Resource will be listed still, but state will be changed and healthcheck will fail
% as the worker no longer exists. % as the worker no longer exists.
{ok, ?CONNECTOR_RESOURCE_GROUP, #{ {ok, ?CONNECTOR_RESOURCE_GROUP, #{
state := State, state := State,
status := StoppedStatus status := StoppedStatus
}} = }} =
emqx_resource:get_instance(PoolName), emqx_resource:get_instance(ResourceId),
?assertEqual(stopped, StoppedStatus), ?assertEqual(stopped, StoppedStatus),
?assertEqual({error, resource_is_stopped}, emqx_resource:health_check(PoolName)), ?assertEqual({error, resource_is_stopped}, emqx_resource:health_check(ResourceId)),
% Resource healthcheck shortcuts things by checking ets. Go deeper by checking pool itself. % Resource healthcheck shortcuts things by checking ets. Go deeper by checking pool itself.
?assertEqual({error, not_found}, ecpool:stop_sup_pool(ReturnedPoolName)), ?assertEqual({error, not_found}, ecpool:stop_sup_pool(PoolName)),
% Can call stop/1 again on an already stopped instance % Can call stop/1 again on an already stopped instance
?assertEqual(ok, emqx_resource:stop(PoolName)), ?assertEqual(ok, emqx_resource:stop(ResourceId)),
% Make sure it can be restarted and the healthchecks and queries work properly % Make sure it can be restarted and the healthchecks and queries work properly
?assertEqual(ok, emqx_resource:restart(PoolName)), ?assertEqual(ok, emqx_resource:restart(ResourceId)),
% async restart, need to wait resource % async restart, need to wait resource
timer:sleep(500), timer:sleep(500),
{ok, ?CONNECTOR_RESOURCE_GROUP, #{status := InitialStatus}} = {ok, ?CONNECTOR_RESOURCE_GROUP, #{status := InitialStatus}} =
emqx_resource:get_instance(PoolName), emqx_resource:get_instance(ResourceId),
?assertEqual({ok, connected}, emqx_resource:health_check(PoolName)), ?assertEqual({ok, connected}, emqx_resource:health_check(ResourceId)),
?assertMatch({ok, []}, emqx_resource:query(PoolName, test_query_find())), ?assertMatch({ok, []}, emqx_resource:query(ResourceId, test_query_find())),
?assertMatch({ok, undefined}, emqx_resource:query(PoolName, test_query_find_one())), ?assertMatch({ok, undefined}, emqx_resource:query(ResourceId, test_query_find_one())),
% Stop and remove the resource in one go. % Stop and remove the resource in one go.
?assertEqual(ok, emqx_resource:remove_local(PoolName)), ?assertEqual(ok, emqx_resource:remove_local(ResourceId)),
?assertEqual({error, not_found}, ecpool:stop_sup_pool(ReturnedPoolName)), ?assertEqual({error, not_found}, ecpool:stop_sup_pool(PoolName)),
% Should not even be able to get the resource data out of ets now unlike just stopping. % Should not even be able to get the resource data out of ets now unlike just stopping.
?assertEqual({error, not_found}, emqx_resource:get_instance(PoolName)). ?assertEqual({error, not_found}, emqx_resource:get_instance(ResourceId)).
% %%------------------------------------------------------------------------------ % %%------------------------------------------------------------------------------
% %% Helpers % %% Helpers

View File

@ -64,14 +64,14 @@ t_lifecycle(_Config) ->
mysql_config() mysql_config()
). ).
perform_lifecycle_check(PoolName, InitialConfig) -> perform_lifecycle_check(ResourceId, InitialConfig) ->
{ok, #{config := CheckedConfig}} = {ok, #{config := CheckedConfig}} =
emqx_resource:check_config(?MYSQL_RESOURCE_MOD, InitialConfig), emqx_resource:check_config(?MYSQL_RESOURCE_MOD, InitialConfig),
{ok, #{ {ok, #{
state := #{poolname := ReturnedPoolName} = State, state := #{pool_name := PoolName} = State,
status := InitialStatus status := InitialStatus
}} = emqx_resource:create_local( }} = emqx_resource:create_local(
PoolName, ResourceId,
?CONNECTOR_RESOURCE_GROUP, ?CONNECTOR_RESOURCE_GROUP,
?MYSQL_RESOURCE_MOD, ?MYSQL_RESOURCE_MOD,
CheckedConfig, CheckedConfig,
@ -83,53 +83,53 @@ perform_lifecycle_check(PoolName, InitialConfig) ->
state := State, state := State,
status := InitialStatus status := InitialStatus
}} = }} =
emqx_resource:get_instance(PoolName), emqx_resource:get_instance(ResourceId),
?assertEqual({ok, connected}, emqx_resource:health_check(PoolName)), ?assertEqual({ok, connected}, emqx_resource:health_check(ResourceId)),
% % Perform query as further check that the resource is working as expected % % Perform query as further check that the resource is working as expected
?assertMatch({ok, _, [[1]]}, emqx_resource:query(PoolName, test_query_no_params())), ?assertMatch({ok, _, [[1]]}, emqx_resource:query(ResourceId, test_query_no_params())),
?assertMatch({ok, _, [[1]]}, emqx_resource:query(PoolName, test_query_with_params())), ?assertMatch({ok, _, [[1]]}, emqx_resource:query(ResourceId, test_query_with_params())),
?assertMatch( ?assertMatch(
{ok, _, [[1]]}, {ok, _, [[1]]},
emqx_resource:query( emqx_resource:query(
PoolName, ResourceId,
test_query_with_params_and_timeout() test_query_with_params_and_timeout()
) )
), ),
?assertEqual(ok, emqx_resource:stop(PoolName)), ?assertEqual(ok, emqx_resource:stop(ResourceId)),
% Resource will be listed still, but state will be changed and healthcheck will fail % Resource will be listed still, but state will be changed and healthcheck will fail
% as the worker no longer exists. % as the worker no longer exists.
{ok, ?CONNECTOR_RESOURCE_GROUP, #{ {ok, ?CONNECTOR_RESOURCE_GROUP, #{
state := State, state := State,
status := StoppedStatus status := StoppedStatus
}} = }} =
emqx_resource:get_instance(PoolName), emqx_resource:get_instance(ResourceId),
?assertEqual(stopped, StoppedStatus), ?assertEqual(stopped, StoppedStatus),
?assertEqual({error, resource_is_stopped}, emqx_resource:health_check(PoolName)), ?assertEqual({error, resource_is_stopped}, emqx_resource:health_check(ResourceId)),
% Resource healthcheck shortcuts things by checking ets. Go deeper by checking pool itself. % Resource healthcheck shortcuts things by checking ets. Go deeper by checking pool itself.
?assertEqual({error, not_found}, ecpool:stop_sup_pool(ReturnedPoolName)), ?assertEqual({error, not_found}, ecpool:stop_sup_pool(PoolName)),
% Can call stop/1 again on an already stopped instance % Can call stop/1 again on an already stopped instance
?assertEqual(ok, emqx_resource:stop(PoolName)), ?assertEqual(ok, emqx_resource:stop(ResourceId)),
% Make sure it can be restarted and the healthchecks and queries work properly % Make sure it can be restarted and the healthchecks and queries work properly
?assertEqual(ok, emqx_resource:restart(PoolName)), ?assertEqual(ok, emqx_resource:restart(ResourceId)),
% async restart, need to wait resource % async restart, need to wait resource
timer:sleep(500), timer:sleep(500),
{ok, ?CONNECTOR_RESOURCE_GROUP, #{status := InitialStatus}} = {ok, ?CONNECTOR_RESOURCE_GROUP, #{status := InitialStatus}} =
emqx_resource:get_instance(PoolName), emqx_resource:get_instance(ResourceId),
?assertEqual({ok, connected}, emqx_resource:health_check(PoolName)), ?assertEqual({ok, connected}, emqx_resource:health_check(ResourceId)),
?assertMatch({ok, _, [[1]]}, emqx_resource:query(PoolName, test_query_no_params())), ?assertMatch({ok, _, [[1]]}, emqx_resource:query(ResourceId, test_query_no_params())),
?assertMatch({ok, _, [[1]]}, emqx_resource:query(PoolName, test_query_with_params())), ?assertMatch({ok, _, [[1]]}, emqx_resource:query(ResourceId, test_query_with_params())),
?assertMatch( ?assertMatch(
{ok, _, [[1]]}, {ok, _, [[1]]},
emqx_resource:query( emqx_resource:query(
PoolName, ResourceId,
test_query_with_params_and_timeout() test_query_with_params_and_timeout()
) )
), ),
% Stop and remove the resource in one go. % Stop and remove the resource in one go.
?assertEqual(ok, emqx_resource:remove_local(PoolName)), ?assertEqual(ok, emqx_resource:remove_local(ResourceId)),
?assertEqual({error, not_found}, ecpool:stop_sup_pool(ReturnedPoolName)), ?assertEqual({error, not_found}, ecpool:stop_sup_pool(PoolName)),
% Should not even be able to get the resource data out of ets now unlike just stopping. % Should not even be able to get the resource data out of ets now unlike just stopping.
?assertEqual({error, not_found}, emqx_resource:get_instance(PoolName)). ?assertEqual({error, not_found}, emqx_resource:get_instance(ResourceId)).
% %%------------------------------------------------------------------------------ % %%------------------------------------------------------------------------------
% %% Helpers % %% Helpers

View File

@ -64,15 +64,15 @@ t_lifecycle(_Config) ->
pgsql_config() pgsql_config()
). ).
perform_lifecycle_check(PoolName, InitialConfig) -> perform_lifecycle_check(ResourceId, InitialConfig) ->
{ok, #{config := CheckedConfig}} = {ok, #{config := CheckedConfig}} =
emqx_resource:check_config(?PGSQL_RESOURCE_MOD, InitialConfig), emqx_resource:check_config(?PGSQL_RESOURCE_MOD, InitialConfig),
{ok, #{ {ok, #{
state := #{poolname := ReturnedPoolName} = State, state := #{pool_name := PoolName} = State,
status := InitialStatus status := InitialStatus
}} = }} =
emqx_resource:create_local( emqx_resource:create_local(
PoolName, ResourceId,
?CONNECTOR_RESOURCE_GROUP, ?CONNECTOR_RESOURCE_GROUP,
?PGSQL_RESOURCE_MOD, ?PGSQL_RESOURCE_MOD,
CheckedConfig, CheckedConfig,
@ -84,39 +84,39 @@ perform_lifecycle_check(PoolName, InitialConfig) ->
state := State, state := State,
status := InitialStatus status := InitialStatus
}} = }} =
emqx_resource:get_instance(PoolName), emqx_resource:get_instance(ResourceId),
?assertEqual({ok, connected}, emqx_resource:health_check(PoolName)), ?assertEqual({ok, connected}, emqx_resource:health_check(ResourceId)),
% % Perform query as further check that the resource is working as expected % % Perform query as further check that the resource is working as expected
?assertMatch({ok, _, [{1}]}, emqx_resource:query(PoolName, test_query_no_params())), ?assertMatch({ok, _, [{1}]}, emqx_resource:query(ResourceId, test_query_no_params())),
?assertMatch({ok, _, [{1}]}, emqx_resource:query(PoolName, test_query_with_params())), ?assertMatch({ok, _, [{1}]}, emqx_resource:query(ResourceId, test_query_with_params())),
?assertEqual(ok, emqx_resource:stop(PoolName)), ?assertEqual(ok, emqx_resource:stop(ResourceId)),
% Resource will be listed still, but state will be changed and healthcheck will fail % Resource will be listed still, but state will be changed and healthcheck will fail
% as the worker no longer exists. % as the worker no longer exists.
{ok, ?CONNECTOR_RESOURCE_GROUP, #{ {ok, ?CONNECTOR_RESOURCE_GROUP, #{
state := State, state := State,
status := StoppedStatus status := StoppedStatus
}} = }} =
emqx_resource:get_instance(PoolName), emqx_resource:get_instance(ResourceId),
?assertEqual(stopped, StoppedStatus), ?assertEqual(stopped, StoppedStatus),
?assertEqual({error, resource_is_stopped}, emqx_resource:health_check(PoolName)), ?assertEqual({error, resource_is_stopped}, emqx_resource:health_check(ResourceId)),
% Resource healthcheck shortcuts things by checking ets. Go deeper by checking pool itself. % Resource healthcheck shortcuts things by checking ets. Go deeper by checking pool itself.
?assertEqual({error, not_found}, ecpool:stop_sup_pool(ReturnedPoolName)), ?assertEqual({error, not_found}, ecpool:stop_sup_pool(PoolName)),
% Can call stop/1 again on an already stopped instance % Can call stop/1 again on an already stopped instance
?assertEqual(ok, emqx_resource:stop(PoolName)), ?assertEqual(ok, emqx_resource:stop(ResourceId)),
% Make sure it can be restarted and the healthchecks and queries work properly % Make sure it can be restarted and the healthchecks and queries work properly
?assertEqual(ok, emqx_resource:restart(PoolName)), ?assertEqual(ok, emqx_resource:restart(ResourceId)),
% async restart, need to wait resource % async restart, need to wait resource
timer:sleep(500), timer:sleep(500),
{ok, ?CONNECTOR_RESOURCE_GROUP, #{status := InitialStatus}} = {ok, ?CONNECTOR_RESOURCE_GROUP, #{status := InitialStatus}} =
emqx_resource:get_instance(PoolName), emqx_resource:get_instance(ResourceId),
?assertEqual({ok, connected}, emqx_resource:health_check(PoolName)), ?assertEqual({ok, connected}, emqx_resource:health_check(ResourceId)),
?assertMatch({ok, _, [{1}]}, emqx_resource:query(PoolName, test_query_no_params())), ?assertMatch({ok, _, [{1}]}, emqx_resource:query(ResourceId, test_query_no_params())),
?assertMatch({ok, _, [{1}]}, emqx_resource:query(PoolName, test_query_with_params())), ?assertMatch({ok, _, [{1}]}, emqx_resource:query(ResourceId, test_query_with_params())),
% Stop and remove the resource in one go. % Stop and remove the resource in one go.
?assertEqual(ok, emqx_resource:remove_local(PoolName)), ?assertEqual(ok, emqx_resource:remove_local(ResourceId)),
?assertEqual({error, not_found}, ecpool:stop_sup_pool(ReturnedPoolName)), ?assertEqual({error, not_found}, ecpool:stop_sup_pool(PoolName)),
% Should not even be able to get the resource data out of ets now unlike just stopping. % Should not even be able to get the resource data out of ets now unlike just stopping.
?assertEqual({error, not_found}, emqx_resource:get_instance(PoolName)). ?assertEqual({error, not_found}, emqx_resource:get_instance(ResourceId)).
% %%------------------------------------------------------------------------------ % %%------------------------------------------------------------------------------
% %% Helpers % %% Helpers

View File

@ -102,14 +102,14 @@ t_sentinel_lifecycle(_Config) ->
[<<"PING">>] [<<"PING">>]
). ).
perform_lifecycle_check(PoolName, InitialConfig, RedisCommand) -> perform_lifecycle_check(ResourceId, InitialConfig, RedisCommand) ->
{ok, #{config := CheckedConfig}} = {ok, #{config := CheckedConfig}} =
emqx_resource:check_config(?REDIS_RESOURCE_MOD, InitialConfig), emqx_resource:check_config(?REDIS_RESOURCE_MOD, InitialConfig),
{ok, #{ {ok, #{
state := #{poolname := ReturnedPoolName} = State, state := #{pool_name := PoolName} = State,
status := InitialStatus status := InitialStatus
}} = emqx_resource:create_local( }} = emqx_resource:create_local(
PoolName, ResourceId,
?CONNECTOR_RESOURCE_GROUP, ?CONNECTOR_RESOURCE_GROUP,
?REDIS_RESOURCE_MOD, ?REDIS_RESOURCE_MOD,
CheckedConfig, CheckedConfig,
@ -121,49 +121,49 @@ perform_lifecycle_check(PoolName, InitialConfig, RedisCommand) ->
state := State, state := State,
status := InitialStatus status := InitialStatus
}} = }} =
emqx_resource:get_instance(PoolName), emqx_resource:get_instance(ResourceId),
?assertEqual({ok, connected}, emqx_resource:health_check(PoolName)), ?assertEqual({ok, connected}, emqx_resource:health_check(ResourceId)),
% Perform query as further check that the resource is working as expected % Perform query as further check that the resource is working as expected
?assertEqual({ok, <<"PONG">>}, emqx_resource:query(PoolName, {cmd, RedisCommand})), ?assertEqual({ok, <<"PONG">>}, emqx_resource:query(ResourceId, {cmd, RedisCommand})),
?assertEqual( ?assertEqual(
{ok, [{ok, <<"PONG">>}, {ok, <<"PONG">>}]}, {ok, [{ok, <<"PONG">>}, {ok, <<"PONG">>}]},
emqx_resource:query(PoolName, {cmds, [RedisCommand, RedisCommand]}) emqx_resource:query(ResourceId, {cmds, [RedisCommand, RedisCommand]})
), ),
?assertMatch( ?assertMatch(
{error, {unrecoverable_error, [{ok, <<"PONG">>}, {error, _}]}}, {error, {unrecoverable_error, [{ok, <<"PONG">>}, {error, _}]}},
emqx_resource:query( emqx_resource:query(
PoolName, ResourceId,
{cmds, [RedisCommand, [<<"INVALID_COMMAND">>]]}, {cmds, [RedisCommand, [<<"INVALID_COMMAND">>]]},
#{timeout => 500} #{timeout => 500}
) )
), ),
?assertEqual(ok, emqx_resource:stop(PoolName)), ?assertEqual(ok, emqx_resource:stop(ResourceId)),
% Resource will be listed still, but state will be changed and healthcheck will fail % Resource will be listed still, but state will be changed and healthcheck will fail
% as the worker no longer exists. % as the worker no longer exists.
{ok, ?CONNECTOR_RESOURCE_GROUP, #{ {ok, ?CONNECTOR_RESOURCE_GROUP, #{
state := State, state := State,
status := StoppedStatus status := StoppedStatus
}} = }} =
emqx_resource:get_instance(PoolName), emqx_resource:get_instance(ResourceId),
?assertEqual(stopped, StoppedStatus), ?assertEqual(stopped, StoppedStatus),
?assertEqual({error, resource_is_stopped}, emqx_resource:health_check(PoolName)), ?assertEqual({error, resource_is_stopped}, emqx_resource:health_check(ResourceId)),
% Resource healthcheck shortcuts things by checking ets. Go deeper by checking pool itself. % Resource healthcheck shortcuts things by checking ets. Go deeper by checking pool itself.
?assertEqual({error, not_found}, ecpool:stop_sup_pool(ReturnedPoolName)), ?assertEqual({error, not_found}, ecpool:stop_sup_pool(PoolName)),
% Can call stop/1 again on an already stopped instance % Can call stop/1 again on an already stopped instance
?assertEqual(ok, emqx_resource:stop(PoolName)), ?assertEqual(ok, emqx_resource:stop(ResourceId)),
% Make sure it can be restarted and the healthchecks and queries work properly % Make sure it can be restarted and the healthchecks and queries work properly
?assertEqual(ok, emqx_resource:restart(PoolName)), ?assertEqual(ok, emqx_resource:restart(ResourceId)),
% async restart, need to wait resource % async restart, need to wait resource
timer:sleep(500), timer:sleep(500),
{ok, ?CONNECTOR_RESOURCE_GROUP, #{status := InitialStatus}} = {ok, ?CONNECTOR_RESOURCE_GROUP, #{status := InitialStatus}} =
emqx_resource:get_instance(PoolName), emqx_resource:get_instance(ResourceId),
?assertEqual({ok, connected}, emqx_resource:health_check(PoolName)), ?assertEqual({ok, connected}, emqx_resource:health_check(ResourceId)),
?assertEqual({ok, <<"PONG">>}, emqx_resource:query(PoolName, {cmd, RedisCommand})), ?assertEqual({ok, <<"PONG">>}, emqx_resource:query(ResourceId, {cmd, RedisCommand})),
% Stop and remove the resource in one go. % Stop and remove the resource in one go.
?assertEqual(ok, emqx_resource:remove_local(PoolName)), ?assertEqual(ok, emqx_resource:remove_local(ResourceId)),
?assertEqual({error, not_found}, ecpool:stop_sup_pool(ReturnedPoolName)), ?assertEqual({error, not_found}, ecpool:stop_sup_pool(PoolName)),
% Should not even be able to get the resource data out of ets now unlike just stopping. % Should not even be able to get the resource data out of ets now unlike just stopping.
?assertEqual({error, not_found}, emqx_resource:get_instance(PoolName)). ?assertEqual({error, not_found}, emqx_resource:get_instance(ResourceId)).
% %%------------------------------------------------------------------------------ % %%------------------------------------------------------------------------------
% %% Helpers % %% Helpers

View File

@ -14,31 +14,27 @@
%% limitations under the License. %% limitations under the License.
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
-module(emqx_plugin_libs_pool). -module(emqx_resource_pool).
-export([ -export([
start_pool/3, start/3,
stop_pool/1, stop/1,
pool_name/1, health_check_workers/2,
health_check_ecpool_workers/2, health_check_workers/3
health_check_ecpool_workers/3
]). ]).
-include_lib("emqx/include/logger.hrl"). -include_lib("emqx/include/logger.hrl").
-define(HEALTH_CHECK_TIMEOUT, 15000). -define(HEALTH_CHECK_TIMEOUT, 15000).
pool_name(ID) when is_binary(ID) -> start(Name, Mod, Options) ->
list_to_atom(binary_to_list(ID)).
start_pool(Name, Mod, Options) ->
case ecpool:start_sup_pool(Name, Mod, Options) of case ecpool:start_sup_pool(Name, Mod, Options) of
{ok, _} -> {ok, _} ->
?SLOG(info, #{msg => "start_ecpool_ok", pool_name => Name}), ?SLOG(info, #{msg => "start_ecpool_ok", pool_name => Name}),
ok; ok;
{error, {already_started, _Pid}} -> {error, {already_started, _Pid}} ->
stop_pool(Name), stop(Name),
start_pool(Name, Mod, Options); start(Name, Mod, Options);
{error, Reason} -> {error, Reason} ->
NReason = parse_reason(Reason), NReason = parse_reason(Reason),
?SLOG(error, #{ ?SLOG(error, #{
@ -49,7 +45,7 @@ start_pool(Name, Mod, Options) ->
{error, {start_pool_failed, Name, NReason}} {error, {start_pool_failed, Name, NReason}}
end. end.
stop_pool(Name) -> stop(Name) ->
case ecpool:stop_sup_pool(Name) of case ecpool:stop_sup_pool(Name) of
ok -> ok ->
?SLOG(info, #{msg => "stop_ecpool_ok", pool_name => Name}); ?SLOG(info, #{msg => "stop_ecpool_ok", pool_name => Name});
@ -64,10 +60,10 @@ stop_pool(Name) ->
error({stop_pool_failed, Name, Reason}) error({stop_pool_failed, Name, Reason})
end. end.
health_check_ecpool_workers(PoolName, CheckFunc) -> health_check_workers(PoolName, CheckFunc) ->
health_check_ecpool_workers(PoolName, CheckFunc, ?HEALTH_CHECK_TIMEOUT). health_check_workers(PoolName, CheckFunc, ?HEALTH_CHECK_TIMEOUT).
health_check_ecpool_workers(PoolName, CheckFunc, Timeout) -> health_check_workers(PoolName, CheckFunc, Timeout) ->
Workers = [Worker || {_WorkerName, Worker} <- ecpool:workers(PoolName)], Workers = [Worker || {_WorkerName, Worker} <- ecpool:workers(PoolName)],
DoPerWorker = DoPerWorker =
fun(Worker) -> fun(Worker) ->

View File

@ -917,7 +917,7 @@ t_invalid_private_key(Config) ->
#{<<"private_key">> => InvalidPrivateKeyPEM} #{<<"private_key">> => InvalidPrivateKeyPEM}
} }
), ),
#{?snk_kind := gcp_pubsub_bridge_jwt_worker_failed_to_start}, #{?snk_kind := "gcp_pubsub_bridge_jwt_worker_failed_to_start"},
20_000 20_000
), ),
Res Res
@ -928,7 +928,7 @@ t_invalid_private_key(Config) ->
[#{reason := Reason}] when [#{reason := Reason}] when
Reason =:= noproc orelse Reason =:= noproc orelse
Reason =:= {shutdown, {error, empty_key}}, Reason =:= {shutdown, {error, empty_key}},
?of_kind(gcp_pubsub_bridge_jwt_worker_failed_to_start, Trace) ?of_kind("gcp_pubsub_bridge_jwt_worker_failed_to_start", Trace)
), ),
?assertMatch( ?assertMatch(
[#{error := empty_key}], [#{error := empty_key}],
@ -956,14 +956,14 @@ t_jwt_worker_start_timeout(Config) ->
#{<<"private_key">> => InvalidPrivateKeyPEM} #{<<"private_key">> => InvalidPrivateKeyPEM}
} }
), ),
#{?snk_kind := gcp_pubsub_bridge_jwt_timeout}, #{?snk_kind := "gcp_pubsub_bridge_jwt_timeout"},
20_000 20_000
), ),
Res Res
end, end,
fun(Res, Trace) -> fun(Res, Trace) ->
?assertMatch({ok, _}, Res), ?assertMatch({ok, _}, Res),
?assertMatch([_], ?of_kind(gcp_pubsub_bridge_jwt_timeout, Trace)), ?assertMatch([_], ?of_kind("gcp_pubsub_bridge_jwt_timeout", Trace)),
ok ok
end end
), ),
@ -1329,7 +1329,7 @@ t_failed_to_start_jwt_worker(Config) ->
fun(Trace) -> fun(Trace) ->
?assertMatch( ?assertMatch(
[#{reason := {error, restarting}}], [#{reason := {error, restarting}}],
?of_kind(gcp_pubsub_bridge_jwt_worker_failed_to_start, Trace) ?of_kind("gcp_pubsub_bridge_jwt_worker_failed_to_start", Trace)
), ),
ok ok
end end

View File

@ -265,7 +265,7 @@ unprepare(Config, Key) ->
Name = ?config(mysql_name, Config), Name = ?config(mysql_name, Config),
BridgeType = ?config(mysql_bridge_type, Config), BridgeType = ?config(mysql_bridge_type, Config),
ResourceID = emqx_bridge_resource:resource_id(BridgeType, Name), ResourceID = emqx_bridge_resource:resource_id(BridgeType, Name),
{ok, _, #{state := #{poolname := PoolName}}} = emqx_resource:get_instance(ResourceID), {ok, _, #{state := #{pool_name := PoolName}}} = emqx_resource:get_instance(ResourceID),
[ [
begin begin
{ok, Conn} = ecpool_worker:client(Worker), {ok, Conn} = ecpool_worker:client(Worker),

View File

@ -44,7 +44,7 @@
-type state() :: -type state() ::
#{ #{
poolname := atom(), pool_name := binary(),
prepare_cql := prepares(), prepare_cql := prepares(),
params_tokens := params_tokens(), params_tokens := params_tokens(),
%% returned by ecql:prepare/2 %% returned by ecql:prepare/2
@ -124,14 +124,10 @@ on_start(
false -> false ->
[] []
end, end,
%% use InstaId of binary type as Pool name, which is supported in ecpool. State = parse_prepare_cql(Config),
PoolName = InstId, case emqx_resource_pool:start(InstId, ?MODULE, Options ++ SslOpts) of
Prepares = parse_prepare_cql(Config),
InitState = #{poolname => PoolName, prepare_statement => #{}},
State = maps:merge(InitState, Prepares),
case emqx_plugin_libs_pool:start_pool(PoolName, ?MODULE, Options ++ SslOpts) of
ok -> ok ->
{ok, init_prepare(State)}; {ok, init_prepare(State#{pool_name => InstId, prepare_statement => #{}})};
{error, Reason} -> {error, Reason} ->
?tp( ?tp(
cassandra_connector_start_failed, cassandra_connector_start_failed,
@ -140,12 +136,12 @@ on_start(
{error, Reason} {error, Reason}
end. end.
on_stop(InstId, #{poolname := PoolName}) -> on_stop(InstId, #{pool_name := PoolName}) ->
?SLOG(info, #{ ?SLOG(info, #{
msg => "stopping_cassandra_connector", msg => "stopping_cassandra_connector",
connector => InstId connector => InstId
}), }),
emqx_plugin_libs_pool:stop_pool(PoolName). emqx_resource_pool:stop(PoolName).
-type request() :: -type request() ::
% emqx_bridge.erl % emqx_bridge.erl
@ -184,7 +180,7 @@ do_single_query(
InstId, InstId,
Request, Request,
Async, Async,
#{poolname := PoolName} = State #{pool_name := PoolName} = State
) -> ) ->
{Type, PreparedKeyOrSQL, Params} = parse_request_to_cql(Request), {Type, PreparedKeyOrSQL, Params} = parse_request_to_cql(Request),
?tp( ?tp(
@ -232,7 +228,7 @@ do_batch_query(
InstId, InstId,
Requests, Requests,
Async, Async,
#{poolname := PoolName} = State #{pool_name := PoolName} = State
) -> ) ->
CQLs = CQLs =
lists:map( lists:map(
@ -305,8 +301,8 @@ exec_cql_batch_query(InstId, PoolName, Async, CQLs) ->
Result Result
end. end.
on_get_status(_InstId, #{poolname := Pool} = State) -> on_get_status(_InstId, #{pool_name := PoolName} = State) ->
case emqx_plugin_libs_pool:health_check_ecpool_workers(Pool, fun ?MODULE:do_get_status/1) of case emqx_resource_pool:health_check_workers(PoolName, fun ?MODULE:do_get_status/1) of
true -> true ->
case do_check_prepares(State) of case do_check_prepares(State) of
ok -> ok ->
@ -327,7 +323,7 @@ do_get_status(Conn) ->
do_check_prepares(#{prepare_cql := Prepares}) when is_map(Prepares) -> do_check_prepares(#{prepare_cql := Prepares}) when is_map(Prepares) ->
ok; ok;
do_check_prepares(State = #{poolname := PoolName, prepare_cql := {error, Prepares}}) -> do_check_prepares(State = #{pool_name := PoolName, prepare_cql := {error, Prepares}}) ->
%% retry to prepare %% retry to prepare
case prepare_cql(Prepares, PoolName) of case prepare_cql(Prepares, PoolName) of
{ok, Sts} -> {ok, Sts} ->
@ -397,7 +393,7 @@ parse_prepare_cql([], Prepares, Tokens) ->
params_tokens => Tokens params_tokens => Tokens
}. }.
init_prepare(State = #{prepare_cql := Prepares, poolname := PoolName}) -> init_prepare(State = #{prepare_cql := Prepares, pool_name := PoolName}) ->
case maps:size(Prepares) of case maps:size(Prepares) of
0 -> 0 ->
State; State;
@ -429,17 +425,17 @@ prepare_cql(Prepares, PoolName) ->
end. end.
do_prepare_cql(Prepares, PoolName) -> do_prepare_cql(Prepares, PoolName) ->
do_prepare_cql(ecpool:workers(PoolName), Prepares, PoolName, #{}). do_prepare_cql(ecpool:workers(PoolName), Prepares, #{}).
do_prepare_cql([{_Name, Worker} | T], Prepares, PoolName, _LastSts) -> do_prepare_cql([{_Name, Worker} | T], Prepares, _LastSts) ->
{ok, Conn} = ecpool_worker:client(Worker), {ok, Conn} = ecpool_worker:client(Worker),
case prepare_cql_to_conn(Conn, Prepares) of case prepare_cql_to_conn(Conn, Prepares) of
{ok, Sts} -> {ok, Sts} ->
do_prepare_cql(T, Prepares, PoolName, Sts); do_prepare_cql(T, Prepares, Sts);
Error -> Error ->
Error Error
end; end;
do_prepare_cql([], _Prepares, _PoolName, LastSts) -> do_prepare_cql([], _Prepares, LastSts) ->
{ok, LastSts}. {ok, LastSts}.
prepare_cql_to_conn(Conn, Prepares) -> prepare_cql_to_conn(Conn, Prepares) ->

View File

@ -62,7 +62,8 @@
-type state() :: -type state() ::
#{ #{
templates := templates(), templates := templates(),
poolname := atom() pool_name := binary(),
connect_timeout := pos_integer()
}. }.
-type clickhouse_config() :: map(). -type clickhouse_config() :: map().
@ -141,7 +142,6 @@ on_start(
connector => InstanceID, connector => InstanceID,
config => emqx_utils:redact(Config) config => emqx_utils:redact(Config)
}), }),
PoolName = emqx_plugin_libs_pool:pool_name(InstanceID),
Options = [ Options = [
{url, URL}, {url, URL},
{user, maps:get(username, Config, "default")}, {user, maps:get(username, Config, "default")},
@ -149,46 +149,43 @@ on_start(
{database, DB}, {database, DB},
{auto_reconnect, ?AUTO_RECONNECT_INTERVAL}, {auto_reconnect, ?AUTO_RECONNECT_INTERVAL},
{pool_size, PoolSize}, {pool_size, PoolSize},
{pool, PoolName} {pool, InstanceID}
], ],
InitState = #{
poolname => PoolName,
connect_timeout => ConnectTimeout
},
try try
Templates = prepare_sql_templates(Config), Templates = prepare_sql_templates(Config),
State = maps:merge(InitState, #{templates => Templates}), State = #{
case emqx_plugin_libs_pool:start_pool(PoolName, ?MODULE, Options) of pool_name => InstanceID,
templates => Templates,
connect_timeout => ConnectTimeout
},
case emqx_resource_pool:start(InstanceID, ?MODULE, Options) of
ok -> ok ->
{ok, State}; {ok, State};
{error, Reason} -> {error, Reason} ->
log_start_error(Config, Reason, none), ?tp(
info,
"clickhouse_connector_start_failed",
#{
error => Reason,
config => emqx_utils:redact(Config)
}
),
{error, Reason} {error, Reason}
end end
catch catch
_:CatchReason:Stacktrace -> _:CatchReason:Stacktrace ->
log_start_error(Config, CatchReason, Stacktrace), ?tp(
info,
"clickhouse_connector_start_failed",
#{
error => CatchReason,
stacktrace => Stacktrace,
config => emqx_utils:redact(Config)
}
),
{error, CatchReason} {error, CatchReason}
end. end.
log_start_error(Config, Reason, Stacktrace) ->
StacktraceMap =
case Stacktrace of
none -> #{};
_ -> #{stacktrace => Stacktrace}
end,
LogMessage =
#{
msg => "clickhouse_connector_start_failed",
error_reason => Reason,
config => emqx_utils:redact(Config)
},
?SLOG(info, maps:merge(LogMessage, StacktraceMap)),
?tp(
clickhouse_connector_start_failed,
#{error => Reason}
).
%% Helper functions to prepare SQL tempaltes %% Helper functions to prepare SQL tempaltes
prepare_sql_templates(#{ prepare_sql_templates(#{
@ -240,7 +237,7 @@ split_clickhouse_insert_sql(SQL) ->
end. end.
% This is a callback for ecpool which is triggered by the call to % This is a callback for ecpool which is triggered by the call to
% emqx_plugin_libs_pool:start_pool in on_start/2 % emqx_resource_pool:start in on_start/2
connect(Options) -> connect(Options) ->
URL = iolist_to_binary(emqx_http_lib:normalize(proplists:get_value(url, Options))), URL = iolist_to_binary(emqx_http_lib:normalize(proplists:get_value(url, Options))),
@ -277,23 +274,20 @@ connect(Options) ->
-spec on_stop(resource_id(), resource_state()) -> term(). -spec on_stop(resource_id(), resource_state()) -> term().
on_stop(ResourceID, #{poolname := PoolName}) -> on_stop(InstanceID, #{pool_name := PoolName}) ->
?SLOG(info, #{ ?SLOG(info, #{
msg => "stopping clickouse connector", msg => "stopping clickouse connector",
connector => ResourceID connector => InstanceID
}), }),
emqx_plugin_libs_pool:stop_pool(PoolName). emqx_resource_pool:stop(PoolName).
%% ------------------------------------------------------------------- %% -------------------------------------------------------------------
%% on_get_status emqx_resouce callback and related functions %% on_get_status emqx_resouce callback and related functions
%% ------------------------------------------------------------------- %% -------------------------------------------------------------------
on_get_status( on_get_status(
_InstId, _InstanceID,
#{ #{pool_name := PoolName, connect_timeout := Timeout} = State
poolname := PoolName,
connect_timeout := Timeout
} = State
) -> ) ->
case do_get_status(PoolName, Timeout) of case do_get_status(PoolName, Timeout) of
ok -> ok ->
@ -352,7 +346,7 @@ do_get_status(PoolName, Timeout) ->
on_query( on_query(
ResourceID, ResourceID,
{RequestType, DataOrSQL}, {RequestType, DataOrSQL},
#{poolname := PoolName} = State #{pool_name := PoolName} = State
) -> ) ->
?SLOG(debug, #{ ?SLOG(debug, #{
msg => "clickhouse connector received sql query", msg => "clickhouse connector received sql query",
@ -391,16 +385,11 @@ query_type(send_message) ->
on_batch_query( on_batch_query(
ResourceID, ResourceID,
BatchReq, BatchReq,
State #{pool_name := PoolName, templates := Templates} = _State
) -> ) ->
%% Currently we only support batch requests with the send_message key %% Currently we only support batch requests with the send_message key
{Keys, ObjectsToInsert} = lists:unzip(BatchReq), {Keys, ObjectsToInsert} = lists:unzip(BatchReq),
ensure_keys_are_of_type_send_message(Keys), ensure_keys_are_of_type_send_message(Keys),
%% Pick out the SQL template
#{
templates := Templates,
poolname := PoolName
} = State,
%% Create batch insert SQL statement %% Create batch insert SQL statement
SQL = objects_to_sql(ObjectsToInsert, Templates), SQL = objects_to_sql(ObjectsToInsert, Templates),
%% Do the actual query in the database %% Do the actual query in the database

View File

@ -114,23 +114,23 @@ on_start(
Templates = parse_template(Config), Templates = parse_template(Config),
State = #{ State = #{
poolname => InstanceId, pool_name => InstanceId,
database => Database, database => Database,
templates => Templates templates => Templates
}, },
case emqx_plugin_libs_pool:start_pool(InstanceId, ?MODULE, Options) of case emqx_resource_pool:start(InstanceId, ?MODULE, Options) of
ok -> ok ->
{ok, State}; {ok, State};
Error -> Error ->
Error Error
end. end.
on_stop(InstanceId, #{poolname := PoolName} = _State) -> on_stop(InstanceId, #{pool_name := PoolName}) ->
?SLOG(info, #{ ?SLOG(info, #{
msg => "stopping_dynamo_connector", msg => "stopping_dynamo_connector",
connector => InstanceId connector => InstanceId
}), }),
emqx_plugin_libs_pool:stop_pool(PoolName). emqx_resource_pool:stop(PoolName).
on_query(InstanceId, Query, State) -> on_query(InstanceId, Query, State) ->
do_query(InstanceId, Query, handover, State). do_query(InstanceId, Query, handover, State).
@ -160,8 +160,8 @@ on_batch_query_async(InstanceId, [{send_message, _} | _] = Query, Reply, State)
on_batch_query_async(_InstanceId, Query, _Reply, _State) -> on_batch_query_async(_InstanceId, Query, _Reply, _State) ->
{error, {unrecoverable_error, {invalid_request, Query}}}. {error, {unrecoverable_error, {invalid_request, Query}}}.
on_get_status(_InstanceId, #{poolname := Pool}) -> on_get_status(_InstanceId, #{pool_name := PoolName}) ->
Health = emqx_plugin_libs_pool:health_check_ecpool_workers(Pool, fun ?MODULE:do_get_status/1), Health = emqx_resource_pool:health_check_workers(PoolName, fun ?MODULE:do_get_status/1),
status_result(Health). status_result(Health).
do_get_status(_Conn) -> do_get_status(_Conn) ->
@ -183,7 +183,7 @@ do_query(
InstanceId, InstanceId,
Query, Query,
ApplyMode, ApplyMode,
#{poolname := PoolName, templates := Templates, database := Database} = State #{pool_name := PoolName, templates := Templates, database := Database} = State
) -> ) ->
?TRACE( ?TRACE(
"QUERY", "QUERY",

View File

@ -26,7 +26,6 @@
]). ]).
-export([reply_delegator/3]). -export([reply_delegator/3]).
-type bridge_id() :: binary().
-type jwt_worker() :: binary(). -type jwt_worker() :: binary().
-type service_account_json() :: emqx_ee_bridge_gcp_pubsub:service_account_json(). -type service_account_json() :: emqx_ee_bridge_gcp_pubsub:service_account_json().
-type config() :: #{ -type config() :: #{
@ -43,7 +42,7 @@
jwt_worker_id := jwt_worker(), jwt_worker_id := jwt_worker(),
max_retries := non_neg_integer(), max_retries := non_neg_integer(),
payload_template := emqx_plugin_libs_rule:tmpl_token(), payload_template := emqx_plugin_libs_rule:tmpl_token(),
pool_name := atom(), pool_name := binary(),
project_id := binary(), project_id := binary(),
pubsub_topic := binary(), pubsub_topic := binary(),
request_timeout := timer:time() request_timeout := timer:time()
@ -102,14 +101,13 @@ on_start(
jwt_worker_id := JWTWorkerId, jwt_worker_id := JWTWorkerId,
project_id := ProjectId project_id := ProjectId
} = ensure_jwt_worker(InstanceId, Config), } = ensure_jwt_worker(InstanceId, Config),
PoolName = emqx_plugin_libs_pool:pool_name(InstanceId),
State = #{ State = #{
connect_timeout => ConnectTimeout, connect_timeout => ConnectTimeout,
instance_id => InstanceId, instance_id => InstanceId,
jwt_worker_id => JWTWorkerId, jwt_worker_id => JWTWorkerId,
max_retries => MaxRetries, max_retries => MaxRetries,
payload_template => emqx_plugin_libs_rule:preproc_tmpl(PayloadTemplate), payload_template => emqx_plugin_libs_rule:preproc_tmpl(PayloadTemplate),
pool_name => PoolName, pool_name => InstanceId,
project_id => ProjectId, project_id => ProjectId,
pubsub_topic => PubSubTopic, pubsub_topic => PubSubTopic,
request_timeout => RequestTimeout request_timeout => RequestTimeout
@ -118,20 +116,20 @@ on_start(
gcp_pubsub_on_start_before_starting_pool, gcp_pubsub_on_start_before_starting_pool,
#{ #{
instance_id => InstanceId, instance_id => InstanceId,
pool_name => PoolName, pool_name => InstanceId,
pool_opts => PoolOpts pool_opts => PoolOpts
} }
), ),
?tp(gcp_pubsub_starting_ehttpc_pool, #{pool_name => PoolName}), ?tp(gcp_pubsub_starting_ehttpc_pool, #{pool_name => InstanceId}),
case ehttpc_sup:start_pool(PoolName, PoolOpts) of case ehttpc_sup:start_pool(InstanceId, PoolOpts) of
{ok, _} -> {ok, _} ->
{ok, State}; {ok, State};
{error, {already_started, _}} -> {error, {already_started, _}} ->
?tp(gcp_pubsub_ehttpc_pool_already_started, #{pool_name => PoolName}), ?tp(gcp_pubsub_ehttpc_pool_already_started, #{pool_name => InstanceId}),
{ok, State}; {ok, State};
{error, Reason} -> {error, Reason} ->
?tp(gcp_pubsub_ehttpc_pool_start_failure, #{ ?tp(gcp_pubsub_ehttpc_pool_start_failure, #{
pool_name => PoolName, pool_name => InstanceId,
reason => Reason reason => Reason
}), }),
{error, Reason} {error, Reason}
@ -140,10 +138,7 @@ on_start(
-spec on_stop(manager_id(), state()) -> ok | {error, term()}. -spec on_stop(manager_id(), state()) -> ok | {error, term()}.
on_stop( on_stop(
InstanceId, InstanceId,
_State = #{ _State = #{jwt_worker_id := JWTWorkerId, pool_name := PoolName}
jwt_worker_id := JWTWorkerId,
pool_name := PoolName
}
) -> ) ->
?tp(gcp_pubsub_stop, #{instance_id => InstanceId, jwt_worker_id => JWTWorkerId}), ?tp(gcp_pubsub_stop, #{instance_id => InstanceId, jwt_worker_id => JWTWorkerId}),
?SLOG(info, #{ ?SLOG(info, #{
@ -155,7 +150,7 @@ on_stop(
ehttpc_sup:stop_pool(PoolName). ehttpc_sup:stop_pool(PoolName).
-spec on_query( -spec on_query(
bridge_id(), resource_id(),
{send_message, map()}, {send_message, map()},
state() state()
) -> ) ->
@ -163,32 +158,32 @@ on_stop(
| {ok, status_code(), headers(), body()} | {ok, status_code(), headers(), body()}
| {error, {recoverable_error, term()}} | {error, {recoverable_error, term()}}
| {error, term()}. | {error, term()}.
on_query(BridgeId, {send_message, Selected}, State) -> on_query(ResourceId, {send_message, Selected}, State) ->
Requests = [{send_message, Selected}], Requests = [{send_message, Selected}],
?TRACE( ?TRACE(
"QUERY_SYNC", "QUERY_SYNC",
"gcp_pubsub_received", "gcp_pubsub_received",
#{requests => Requests, connector => BridgeId, state => State} #{requests => Requests, connector => ResourceId, state => State}
), ),
do_send_requests_sync(State, Requests, BridgeId). do_send_requests_sync(State, Requests, ResourceId).
-spec on_query_async( -spec on_query_async(
bridge_id(), resource_id(),
{send_message, map()}, {send_message, map()},
{ReplyFun :: function(), Args :: list()}, {ReplyFun :: function(), Args :: list()},
state() state()
) -> {ok, pid()}. ) -> {ok, pid()}.
on_query_async(BridgeId, {send_message, Selected}, ReplyFunAndArgs, State) -> on_query_async(ResourceId, {send_message, Selected}, ReplyFunAndArgs, State) ->
Requests = [{send_message, Selected}], Requests = [{send_message, Selected}],
?TRACE( ?TRACE(
"QUERY_ASYNC", "QUERY_ASYNC",
"gcp_pubsub_received", "gcp_pubsub_received",
#{requests => Requests, connector => BridgeId, state => State} #{requests => Requests, connector => ResourceId, state => State}
), ),
do_send_requests_async(State, Requests, ReplyFunAndArgs, BridgeId). do_send_requests_async(State, Requests, ReplyFunAndArgs, ResourceId).
-spec on_batch_query( -spec on_batch_query(
bridge_id(), resource_id(),
[{send_message, map()}], [{send_message, map()}],
state() state()
) -> ) ->
@ -196,34 +191,30 @@ on_query_async(BridgeId, {send_message, Selected}, ReplyFunAndArgs, State) ->
| {ok, status_code(), headers(), body()} | {ok, status_code(), headers(), body()}
| {error, {recoverable_error, term()}} | {error, {recoverable_error, term()}}
| {error, term()}. | {error, term()}.
on_batch_query(BridgeId, Requests, State) -> on_batch_query(ResourceId, Requests, State) ->
?TRACE( ?TRACE(
"QUERY_SYNC", "QUERY_SYNC",
"gcp_pubsub_received", "gcp_pubsub_received",
#{requests => Requests, connector => BridgeId, state => State} #{requests => Requests, connector => ResourceId, state => State}
), ),
do_send_requests_sync(State, Requests, BridgeId). do_send_requests_sync(State, Requests, ResourceId).
-spec on_batch_query_async( -spec on_batch_query_async(
bridge_id(), resource_id(),
[{send_message, map()}], [{send_message, map()}],
{ReplyFun :: function(), Args :: list()}, {ReplyFun :: function(), Args :: list()},
state() state()
) -> {ok, pid()}. ) -> {ok, pid()}.
on_batch_query_async(BridgeId, Requests, ReplyFunAndArgs, State) -> on_batch_query_async(ResourceId, Requests, ReplyFunAndArgs, State) ->
?TRACE( ?TRACE(
"QUERY_ASYNC", "QUERY_ASYNC",
"gcp_pubsub_received", "gcp_pubsub_received",
#{requests => Requests, connector => BridgeId, state => State} #{requests => Requests, connector => ResourceId, state => State}
), ),
do_send_requests_async(State, Requests, ReplyFunAndArgs, BridgeId). do_send_requests_async(State, Requests, ReplyFunAndArgs, ResourceId).
-spec on_get_status(manager_id(), state()) -> connected | disconnected. -spec on_get_status(manager_id(), state()) -> connected | disconnected.
on_get_status(InstanceId, State) -> on_get_status(InstanceId, #{connect_timeout := Timeout, pool_name := PoolName} = State) ->
#{
connect_timeout := Timeout,
pool_name := PoolName
} = State,
case do_get_status(InstanceId, PoolName, Timeout) of case do_get_status(InstanceId, PoolName, Timeout) of
true -> true ->
connected; connected;
@ -245,8 +236,7 @@ on_get_status(InstanceId, State) ->
project_id := binary() project_id := binary()
}. }.
ensure_jwt_worker(InstanceId, #{ ensure_jwt_worker(InstanceId, #{
service_account_json := ServiceAccountJSON, service_account_json := ServiceAccountJSON
pubsub_topic := PubSubTopic
}) -> }) ->
#{ #{
project_id := ProjectId, project_id := ProjectId,
@ -276,14 +266,8 @@ ensure_jwt_worker(InstanceId, #{
{ok, Worker0} -> {ok, Worker0} ->
Worker0; Worker0;
Error -> Error ->
?tp( ?tp(error, "gcp_pubsub_bridge_jwt_worker_failed_to_start", #{
gcp_pubsub_bridge_jwt_worker_failed_to_start, connector => InstanceId,
#{instance_id => InstanceId, reason => Error}
),
?SLOG(error, #{
msg => "failed_to_start_gcp_pubsub_jwt_worker",
instance_id => InstanceId,
pubsub_topic => PubSubTopic,
reason => Error reason => Error
}), }),
_ = emqx_connector_jwt_sup:ensure_worker_deleted(JWTWorkerId), _ = emqx_connector_jwt_sup:ensure_worker_deleted(JWTWorkerId),
@ -301,26 +285,14 @@ ensure_jwt_worker(InstanceId, #{
demonitor(MRef, [flush]), demonitor(MRef, [flush]),
ok; ok;
{'DOWN', MRef, process, Worker, Reason} -> {'DOWN', MRef, process, Worker, Reason} ->
?tp( ?tp(error, "gcp_pubsub_bridge_jwt_worker_failed_to_start", #{
gcp_pubsub_bridge_jwt_worker_failed_to_start,
#{
resource_id => InstanceId,
reason => Reason
}
),
?SLOG(error, #{
msg => "gcp_pubsub_bridge_jwt_worker_failed_to_start",
connector => InstanceId, connector => InstanceId,
reason => Reason reason => Reason
}), }),
_ = emqx_connector_jwt_sup:ensure_worker_deleted(JWTWorkerId), _ = emqx_connector_jwt_sup:ensure_worker_deleted(JWTWorkerId),
throw(failed_to_start_jwt_worker) throw(failed_to_start_jwt_worker)
after 10_000 -> after 10_000 ->
?tp(gcp_pubsub_bridge_jwt_timeout, #{resource_id => InstanceId}), ?tp(warning, "gcp_pubsub_bridge_jwt_timeout", #{connector => InstanceId}),
?SLOG(warning, #{
msg => "gcp_pubsub_bridge_jwt_timeout",
connector => InstanceId
}),
demonitor(MRef, [flush]), demonitor(MRef, [flush]),
_ = emqx_connector_jwt_sup:ensure_worker_deleted(JWTWorkerId), _ = emqx_connector_jwt_sup:ensure_worker_deleted(JWTWorkerId),
throw(timeout_creating_jwt) throw(timeout_creating_jwt)
@ -569,7 +541,7 @@ reply_delegator(_ResourceId, ReplyFunAndArgs, Result) ->
emqx_resource:apply_reply_fun(ReplyFunAndArgs, Result) emqx_resource:apply_reply_fun(ReplyFunAndArgs, Result)
end. end.
-spec do_get_status(manager_id(), atom(), timer:time()) -> boolean(). -spec do_get_status(manager_id(), binary(), timer:time()) -> boolean().
do_get_status(InstanceId, PoolName, Timeout) -> do_get_status(InstanceId, PoolName, Timeout) ->
Workers = [Worker || {_WorkerName, Worker} <- ehttpc:workers(PoolName)], Workers = [Worker || {_WorkerName, Worker} <- ehttpc:workers(PoolName)],
DoPerWorker = DoPerWorker =

View File

@ -126,7 +126,7 @@
%% -type size() :: integer(). %% -type size() :: integer().
-type state() :: #{ -type state() :: #{
poolname := binary(), pool_name := binary(),
resource_opts := map(), resource_opts := map(),
sql_templates := map() sql_templates := map()
}. }.
@ -208,17 +208,16 @@ on_start(
{password, Password}, {password, Password},
{driver, Driver}, {driver, Driver},
{database, Database}, {database, Database},
{pool_size, PoolSize}, {pool_size, PoolSize}
{poolname, PoolName}
], ],
State = #{ State = #{
%% also InstanceId %% also InstanceId
poolname => PoolName, pool_name => PoolName,
sql_templates => parse_sql_template(Config), sql_templates => parse_sql_template(Config),
resource_opts => ResourceOpts resource_opts => ResourceOpts
}, },
case emqx_plugin_libs_pool:start_pool(PoolName, ?MODULE, Options) of case emqx_resource_pool:start(PoolName, ?MODULE, Options) of
ok -> ok ->
{ok, State}; {ok, State};
{error, Reason} -> {error, Reason} ->
@ -229,12 +228,12 @@ on_start(
{error, Reason} {error, Reason}
end. end.
on_stop(InstanceId, #{poolname := PoolName} = _State) -> on_stop(InstanceId, #{pool_name := PoolName} = _State) ->
?SLOG(info, #{ ?SLOG(info, #{
msg => "stopping_sqlserver_connector", msg => "stopping_sqlserver_connector",
connector => InstanceId connector => InstanceId
}), }),
emqx_plugin_libs_pool:stop_pool(PoolName). emqx_resource_pool:stop(PoolName).
-spec on_query( -spec on_query(
manager_id(), manager_id(),
@ -265,7 +264,6 @@ on_query_async(
InstanceId, InstanceId,
{?ACTION_SEND_MESSAGE, _Msg} = Query, {?ACTION_SEND_MESSAGE, _Msg} = Query,
ReplyFunAndArgs, ReplyFunAndArgs,
%% #{poolname := PoolName, sql_templates := Templates} = State
State State
) -> ) ->
?TRACE( ?TRACE(
@ -306,10 +304,12 @@ on_batch_query_async(InstanceId, Requests, ReplyFunAndArgs, State) ->
), ),
do_query(InstanceId, Requests, ?ASYNC_QUERY_MODE(ReplyFunAndArgs), State). do_query(InstanceId, Requests, ?ASYNC_QUERY_MODE(ReplyFunAndArgs), State).
on_get_status(_InstanceId, #{poolname := Pool, resource_opts := ResourceOpts} = _State) -> on_get_status(_InstanceId, #{pool_name := PoolName, resource_opts := ResourceOpts} = _State) ->
RequestTimeout = ?REQUEST_TIMEOUT(ResourceOpts), RequestTimeout = ?REQUEST_TIMEOUT(ResourceOpts),
Health = emqx_plugin_libs_pool:health_check_ecpool_workers( Health = emqx_resource_pool:health_check_workers(
Pool, {?MODULE, do_get_status, [RequestTimeout]}, RequestTimeout PoolName,
{?MODULE, do_get_status, [RequestTimeout]},
RequestTimeout
), ),
status_result(Health). status_result(Health).
@ -382,7 +382,7 @@ do_query(
InstanceId, InstanceId,
Query, Query,
ApplyMode, ApplyMode,
#{poolname := PoolName, sql_templates := Templates} = State #{pool_name := PoolName, sql_templates := Templates} = State
) -> ) ->
?TRACE( ?TRACE(
"SINGLE_QUERY_SYNC", "SINGLE_QUERY_SYNC",
@ -425,7 +425,7 @@ do_query(
end. end.
worker_do_insert( worker_do_insert(
Conn, SQL, #{resource_opts := ResourceOpts, poolname := InstanceId} = State Conn, SQL, #{resource_opts := ResourceOpts, pool_name := InstanceId} = State
) -> ) ->
LogMeta = #{connector => InstanceId, state => State}, LogMeta = #{connector => InstanceId, state => State},
try try

View File

@ -107,20 +107,20 @@ on_start(
], ],
Prepares = parse_prepare_sql(Config), Prepares = parse_prepare_sql(Config),
State = maps:merge(Prepares, #{poolname => InstanceId, query_opts => query_opts(Config)}), State = Prepares#{pool_name => InstanceId, query_opts => query_opts(Config)},
case emqx_plugin_libs_pool:start_pool(InstanceId, ?MODULE, Options) of case emqx_resource_pool:start(InstanceId, ?MODULE, Options) of
ok -> ok ->
{ok, State}; {ok, State};
Error -> Error ->
Error Error
end. end.
on_stop(InstanceId, #{poolname := PoolName} = _State) -> on_stop(InstanceId, #{pool_name := PoolName}) ->
?SLOG(info, #{ ?SLOG(info, #{
msg => "stopping_tdengine_connector", msg => "stopping_tdengine_connector",
connector => InstanceId connector => InstanceId
}), }),
emqx_plugin_libs_pool:stop_pool(PoolName). emqx_resource_pool:stop(PoolName).
on_query(InstanceId, {query, SQL}, State) -> on_query(InstanceId, {query, SQL}, State) ->
do_query(InstanceId, SQL, State); do_query(InstanceId, SQL, State);
@ -150,8 +150,8 @@ on_batch_query(
{error, {unrecoverable_error, invalid_request}} {error, {unrecoverable_error, invalid_request}}
end. end.
on_get_status(_InstanceId, #{poolname := Pool}) -> on_get_status(_InstanceId, #{pool_name := PoolName}) ->
Health = emqx_plugin_libs_pool:health_check_ecpool_workers(Pool, fun ?MODULE:do_get_status/1), Health = emqx_resource_pool:health_check_workers(PoolName, fun ?MODULE:do_get_status/1),
status_result(Health). status_result(Health).
do_get_status(Conn) -> do_get_status(Conn) ->
@ -171,7 +171,7 @@ do_batch_insert(InstanceId, BatchReqs, InsertPart, Tokens, State) ->
SQL = emqx_plugin_libs_rule:proc_batch_sql(BatchReqs, InsertPart, Tokens), SQL = emqx_plugin_libs_rule:proc_batch_sql(BatchReqs, InsertPart, Tokens),
do_query(InstanceId, SQL, State). do_query(InstanceId, SQL, State).
do_query(InstanceId, Query, #{poolname := PoolName, query_opts := Opts} = State) -> do_query(InstanceId, Query, #{pool_name := PoolName, query_opts := Opts} = State) ->
?TRACE( ?TRACE(
"QUERY", "QUERY",
"tdengine_connector_received", "tdengine_connector_received",

View File

@ -101,15 +101,15 @@ show(Label, What) ->
erlang:display({Label, What}), erlang:display({Label, What}),
What. What.
perform_lifecycle_check(PoolName, InitialConfig) -> perform_lifecycle_check(ResourceId, InitialConfig) ->
{ok, #{config := CheckedConfig}} = {ok, #{config := CheckedConfig}} =
emqx_resource:check_config(?CASSANDRA_RESOURCE_MOD, InitialConfig), emqx_resource:check_config(?CASSANDRA_RESOURCE_MOD, InitialConfig),
{ok, #{ {ok, #{
state := #{poolname := ReturnedPoolName} = State, state := #{pool_name := PoolName} = State,
status := InitialStatus status := InitialStatus
}} = }} =
emqx_resource:create_local( emqx_resource:create_local(
PoolName, ResourceId,
?CONNECTOR_RESOURCE_GROUP, ?CONNECTOR_RESOURCE_GROUP,
?CASSANDRA_RESOURCE_MOD, ?CASSANDRA_RESOURCE_MOD,
CheckedConfig, CheckedConfig,
@ -121,45 +121,45 @@ perform_lifecycle_check(PoolName, InitialConfig) ->
state := State, state := State,
status := InitialStatus status := InitialStatus
}} = }} =
emqx_resource:get_instance(PoolName), emqx_resource:get_instance(ResourceId),
?assertEqual({ok, connected}, emqx_resource:health_check(PoolName)), ?assertEqual({ok, connected}, emqx_resource:health_check(ResourceId)),
% % Perform query as further check that the resource is working as expected % % Perform query as further check that the resource is working as expected
(fun() -> (fun() ->
erlang:display({pool_name, PoolName}), erlang:display({pool_name, ResourceId}),
QueryNoParamsResWrapper = emqx_resource:query(PoolName, test_query_no_params()), QueryNoParamsResWrapper = emqx_resource:query(ResourceId, test_query_no_params()),
?assertMatch({ok, _}, QueryNoParamsResWrapper) ?assertMatch({ok, _}, QueryNoParamsResWrapper)
end)(), end)(),
?assertEqual(ok, emqx_resource:stop(PoolName)), ?assertEqual(ok, emqx_resource:stop(ResourceId)),
% Resource will be listed still, but state will be changed and healthcheck will fail % Resource will be listed still, but state will be changed and healthcheck will fail
% as the worker no longer exists. % as the worker no longer exists.
{ok, ?CONNECTOR_RESOURCE_GROUP, #{ {ok, ?CONNECTOR_RESOURCE_GROUP, #{
state := State, state := State,
status := StoppedStatus status := StoppedStatus
}} = }} =
emqx_resource:get_instance(PoolName), emqx_resource:get_instance(ResourceId),
?assertEqual(stopped, StoppedStatus), ?assertEqual(stopped, StoppedStatus),
?assertEqual({error, resource_is_stopped}, emqx_resource:health_check(PoolName)), ?assertEqual({error, resource_is_stopped}, emqx_resource:health_check(ResourceId)),
% Resource healthcheck shortcuts things by checking ets. Go deeper by checking pool itself. % Resource healthcheck shortcuts things by checking ets. Go deeper by checking pool itself.
?assertEqual({error, not_found}, ecpool:stop_sup_pool(ReturnedPoolName)), ?assertEqual({error, not_found}, ecpool:stop_sup_pool(PoolName)),
% Can call stop/1 again on an already stopped instance % Can call stop/1 again on an already stopped instance
?assertEqual(ok, emqx_resource:stop(PoolName)), ?assertEqual(ok, emqx_resource:stop(ResourceId)),
% Make sure it can be restarted and the healthchecks and queries work properly % Make sure it can be restarted and the healthchecks and queries work properly
?assertEqual(ok, emqx_resource:restart(PoolName)), ?assertEqual(ok, emqx_resource:restart(ResourceId)),
% async restart, need to wait resource % async restart, need to wait resource
timer:sleep(500), timer:sleep(500),
{ok, ?CONNECTOR_RESOURCE_GROUP, #{status := InitialStatus}} = {ok, ?CONNECTOR_RESOURCE_GROUP, #{status := InitialStatus}} =
emqx_resource:get_instance(PoolName), emqx_resource:get_instance(ResourceId),
?assertEqual({ok, connected}, emqx_resource:health_check(PoolName)), ?assertEqual({ok, connected}, emqx_resource:health_check(ResourceId)),
(fun() -> (fun() ->
QueryNoParamsResWrapper = QueryNoParamsResWrapper =
emqx_resource:query(PoolName, test_query_no_params()), emqx_resource:query(ResourceId, test_query_no_params()),
?assertMatch({ok, _}, QueryNoParamsResWrapper) ?assertMatch({ok, _}, QueryNoParamsResWrapper)
end)(), end)(),
% Stop and remove the resource in one go. % Stop and remove the resource in one go.
?assertEqual(ok, emqx_resource:remove_local(PoolName)), ?assertEqual(ok, emqx_resource:remove_local(ResourceId)),
?assertEqual({error, not_found}, ecpool:stop_sup_pool(ReturnedPoolName)), ?assertEqual({error, not_found}, ecpool:stop_sup_pool(PoolName)),
% Should not even be able to get the resource data out of ets now unlike just stopping. % Should not even be able to get the resource data out of ets now unlike just stopping.
?assertEqual({error, not_found}, emqx_resource:get_instance(PoolName)). ?assertEqual({error, not_found}, emqx_resource:get_instance(ResourceId)).
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
%% utils %% utils

View File

@ -95,15 +95,15 @@ show(Label, What) ->
erlang:display({Label, What}), erlang:display({Label, What}),
What. What.
perform_lifecycle_check(PoolName, InitialConfig) -> perform_lifecycle_check(ResourceID, InitialConfig) ->
{ok, #{config := CheckedConfig}} = {ok, #{config := CheckedConfig}} =
emqx_resource:check_config(?CLICKHOUSE_RESOURCE_MOD, InitialConfig), emqx_resource:check_config(?CLICKHOUSE_RESOURCE_MOD, InitialConfig),
{ok, #{ {ok, #{
state := #{poolname := ReturnedPoolName} = State, state := #{pool_name := PoolName} = State,
status := InitialStatus status := InitialStatus
}} = }} =
emqx_resource:create_local( emqx_resource:create_local(
PoolName, ResourceID,
?CONNECTOR_RESOURCE_GROUP, ?CONNECTOR_RESOURCE_GROUP,
?CLICKHOUSE_RESOURCE_MOD, ?CLICKHOUSE_RESOURCE_MOD,
CheckedConfig, CheckedConfig,
@ -115,49 +115,49 @@ perform_lifecycle_check(PoolName, InitialConfig) ->
state := State, state := State,
status := InitialStatus status := InitialStatus
}} = }} =
emqx_resource:get_instance(PoolName), emqx_resource:get_instance(ResourceID),
?assertEqual({ok, connected}, emqx_resource:health_check(PoolName)), ?assertEqual({ok, connected}, emqx_resource:health_check(ResourceID)),
% % Perform query as further check that the resource is working as expected % % Perform query as further check that the resource is working as expected
(fun() -> (fun() ->
erlang:display({pool_name, PoolName}), erlang:display({pool_name, ResourceID}),
QueryNoParamsResWrapper = emqx_resource:query(PoolName, test_query_no_params()), QueryNoParamsResWrapper = emqx_resource:query(ResourceID, test_query_no_params()),
?assertMatch({ok, _}, QueryNoParamsResWrapper), ?assertMatch({ok, _}, QueryNoParamsResWrapper),
{_, QueryNoParamsRes} = QueryNoParamsResWrapper, {_, QueryNoParamsRes} = QueryNoParamsResWrapper,
?assertMatch(<<"1">>, string:trim(QueryNoParamsRes)) ?assertMatch(<<"1">>, string:trim(QueryNoParamsRes))
end)(), end)(),
?assertEqual(ok, emqx_resource:stop(PoolName)), ?assertEqual(ok, emqx_resource:stop(ResourceID)),
% Resource will be listed still, but state will be changed and healthcheck will fail % Resource will be listed still, but state will be changed and healthcheck will fail
% as the worker no longer exists. % as the worker no longer exists.
{ok, ?CONNECTOR_RESOURCE_GROUP, #{ {ok, ?CONNECTOR_RESOURCE_GROUP, #{
state := State, state := State,
status := StoppedStatus status := StoppedStatus
}} = }} =
emqx_resource:get_instance(PoolName), emqx_resource:get_instance(ResourceID),
?assertEqual(stopped, StoppedStatus), ?assertEqual(stopped, StoppedStatus),
?assertEqual({error, resource_is_stopped}, emqx_resource:health_check(PoolName)), ?assertEqual({error, resource_is_stopped}, emqx_resource:health_check(ResourceID)),
% Resource healthcheck shortcuts things by checking ets. Go deeper by checking pool itself. % Resource healthcheck shortcuts things by checking ets. Go deeper by checking pool itself.
?assertEqual({error, not_found}, ecpool:stop_sup_pool(ReturnedPoolName)), ?assertEqual({error, not_found}, ecpool:stop_sup_pool(PoolName)),
% Can call stop/1 again on an already stopped instance % Can call stop/1 again on an already stopped instance
?assertEqual(ok, emqx_resource:stop(PoolName)), ?assertEqual(ok, emqx_resource:stop(ResourceID)),
% Make sure it can be restarted and the healthchecks and queries work properly % Make sure it can be restarted and the healthchecks and queries work properly
?assertEqual(ok, emqx_resource:restart(PoolName)), ?assertEqual(ok, emqx_resource:restart(ResourceID)),
% async restart, need to wait resource % async restart, need to wait resource
timer:sleep(500), timer:sleep(500),
{ok, ?CONNECTOR_RESOURCE_GROUP, #{status := InitialStatus}} = {ok, ?CONNECTOR_RESOURCE_GROUP, #{status := InitialStatus}} =
emqx_resource:get_instance(PoolName), emqx_resource:get_instance(ResourceID),
?assertEqual({ok, connected}, emqx_resource:health_check(PoolName)), ?assertEqual({ok, connected}, emqx_resource:health_check(ResourceID)),
(fun() -> (fun() ->
QueryNoParamsResWrapper = QueryNoParamsResWrapper =
emqx_resource:query(PoolName, test_query_no_params()), emqx_resource:query(ResourceID, test_query_no_params()),
?assertMatch({ok, _}, QueryNoParamsResWrapper), ?assertMatch({ok, _}, QueryNoParamsResWrapper),
{_, QueryNoParamsRes} = QueryNoParamsResWrapper, {_, QueryNoParamsRes} = QueryNoParamsResWrapper,
?assertMatch(<<"1">>, string:trim(QueryNoParamsRes)) ?assertMatch(<<"1">>, string:trim(QueryNoParamsRes))
end)(), end)(),
% Stop and remove the resource in one go. % Stop and remove the resource in one go.
?assertEqual(ok, emqx_resource:remove_local(PoolName)), ?assertEqual(ok, emqx_resource:remove_local(ResourceID)),
?assertEqual({error, not_found}, ecpool:stop_sup_pool(ReturnedPoolName)), ?assertEqual({error, not_found}, ecpool:stop_sup_pool(PoolName)),
% Should not even be able to get the resource data out of ets now unlike just stopping. % Should not even be able to get the resource data out of ets now unlike just stopping.
?assertEqual({error, not_found}, emqx_resource:get_instance(PoolName)). ?assertEqual({error, not_found}, emqx_resource:get_instance(ResourceID)).
% %%------------------------------------------------------------------------------ % %%------------------------------------------------------------------------------
% %% Helpers % %% Helpers