Packages
hackney
2.0.0-beta.1
4.7.2
4.7.1
4.7.0
4.6.1
4.6.0
4.5.2
4.5.1
4.5.0
4.4.5
4.4.3
4.4.2
4.4.1
4.4.0
4.3.0
4.2.3
4.2.2
4.2.1
4.2.0
4.1.0
4.0.3
4.0.2
4.0.1
4.0.0
3.2.1
3.2.0
3.1.2
3.1.1
3.1.0
3.0.3
3.0.2
3.0.1
3.0.0
retired
2.0.1
2.0.0
2.0.0-beta.1
1.25.0
1.24.1
1.24.0
1.23.0
1.22.0
1.21.0
1.20.1
1.20.0
1.19.1
1.19.0
1.18.2
1.18.1
1.18.0
1.17.4
1.17.3
1.17.2
1.17.1
1.17.0
1.16.0
1.15.2
1.15.1
1.15.0
1.14.3
1.14.2
1.14.0
1.13.0
1.12.1
1.12.0
1.11.0
1.10.1
1.10.0
1.9.0
1.8.6
1.8.5
1.8.4
1.8.3
1.8.2
1.8.0
1.7.1
1.7.0
1.6.6
retired
1.6.5
1.6.4
retired
1.6.3
1.6.2
1.6.1
1.6.0
1.5.7
1.5.6
1.5.5
1.5.4
1.5.3
1.5.2
1.5.1
1.5.0
1.4.10
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.0
1.1.0
1.0.6
1.0.5
1.0.2
1.0.1
0.15.2
0.15.0
0.14.3
0.14.2
0.14.1
0.14.0
0.13.1
Simple HTTP client with HTTP/1.1, HTTP/2, and HTTP/3 support
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
src/hackney_manager.erl
%%% -*- erlang -*-
%%%
%%% This file is part of hackney released under the Apache 2 license.
%%% See the NOTICE for more information.
%%%
%%% Simplified manager that only handles metrics.
%%% Request tracking is no longer needed - hackney_conn processes
%%% manage their own lifecycle and monitor their owners.
-module(hackney_manager).
-behaviour(gen_server).
%% Metrics API
-export([start_request/1,
finish_request/2,
get_metrics_engine/0]).
%% Backward compatibility API
-export([get_state/1, async_response_pid/1]).
%% gen_server API
-export([start_link/0]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
-record(state, {
metrics_engine
}).
%%====================================================================
%% API
%%====================================================================
%% @doc Called when a new request starts. Updates request counters.
-spec start_request(Host :: string() | binary()) -> ok.
start_request(Host) ->
gen_server:cast(?MODULE, {start_request, Host}).
%% @doc Called when a request finishes. Updates metrics.
-spec finish_request(Host :: string() | binary(), StartTime :: erlang:timestamp()) -> ok.
finish_request(Host, StartTime) ->
gen_server:cast(?MODULE, {finish_request, Host, StartTime}).
%% @doc Get the current metrics engine.
-spec get_metrics_engine() -> module().
get_metrics_engine() ->
hackney_metrics:get_engine().
%% @doc Check the state of a connection (backward compatibility).
%% In the old architecture, this tracked request state.
%% In the new architecture, we simply check if the connection process is alive.
%% Returns `req_not_found' if the process is dead, or the connection state.
-spec get_state(pid() | term()) -> req_not_found | term().
get_state(ConnPid) when is_pid(ConnPid) ->
case is_process_alive(ConnPid) of
false -> req_not_found;
true ->
case hackney_conn:get_state(ConnPid) of
{ok, State} -> State;
_ -> req_not_found
end
end;
get_state(_) ->
req_not_found.
%% @doc Check if a connection is in async mode (backward compatibility).
%% In the old architecture, this returned the async response process PID.
%% In the new architecture, we check if the connection process is in async mode.
%% Returns `{error, req_not_async}' if not in async mode.
-spec async_response_pid(pid() | term()) -> {ok, pid()} | {error, req_not_async}.
async_response_pid(ConnPid) when is_pid(ConnPid) ->
case is_process_alive(ConnPid) of
false -> {error, req_not_async};
true ->
case hackney_conn:get_state(ConnPid) of
{ok, State} when State =:= receiving; State =:= streaming ->
{ok, ConnPid};
_ ->
{error, req_not_async}
end
end;
async_response_pid(_) ->
{error, req_not_async}.
%%====================================================================
%% gen_server callbacks
%%====================================================================
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
init([]) ->
%% Initialize metrics
Engine = hackney_metrics:get_engine(),
_ = metrics:new(Engine, counter, [hackney, nb_requests]),
_ = metrics:new(Engine, counter, [hackney, total_requests]),
_ = metrics:new(Engine, counter, [hackney, finished_requests]),
{ok, #state{metrics_engine = Engine}}.
handle_call(_Request, _From, State) ->
{reply, ok, State}.
handle_cast({start_request, Host}, #state{metrics_engine = Engine} = State) ->
_ = metrics:increment_counter(Engine, [hackney, Host, nb_requests]),
_ = metrics:increment_counter(Engine, [hackney, nb_requests]),
_ = metrics:increment_counter(Engine, [hackney, total_requests]),
{noreply, State};
handle_cast({finish_request, Host, StartTime}, #state{metrics_engine = Engine} = State) ->
RequestTime = timer:now_diff(os:timestamp(), StartTime) / 1000,
_ = metrics:update_histogram(Engine, [hackney, Host, request_time], RequestTime),
_ = metrics:decrement_counter(Engine, [hackney, Host, nb_requests]),
_ = metrics:decrement_counter(Engine, [hackney, nb_requests]),
_ = metrics:increment_counter(Engine, [hackney, finished_requests]),
{noreply, State};
handle_cast(_Msg, State) ->
{noreply, State}.
handle_info(_Info, State) ->
{noreply, State}.
terminate(_Reason, _State) ->
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.