Progressor - ΡΡΠΎ Π²ΡΡΠΎΠΊΠΎΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»ΡΠ½Π°Ρ ΡΠΈΡΡΠ΅ΠΌΠ° ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠΈ Π΄ΠΎΠ»Π³ΠΎΠΆΠΈΠ²ΡΡΠΈΡ ΠΏΡΠΎΡΠ΅ΡΡΠΎΠ² Π½Π° ΡΠ·ΡΠΊΠ΅ Erlang/OTP. Π‘ΠΈΡΡΠ΅ΠΌΠ° ΠΏΡΠ΅Π΄Π½Π°Π·Π½Π°ΡΠ΅Π½Π° Π΄Π»Ρ ΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΡ ΠΆΠΈΠ·Π½Π΅Π½Π½ΡΠΌ ΡΠΈΠΊΠ»ΠΎΠΌ ΠΏΡΠΎΡΠ΅ΡΡΠΎΠ², ΠΈΡ ΡΠΎΡΡΠΎΡΠ½ΠΈΠ΅ΠΌ ΠΈ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ΠΌ Π·Π°Π΄Π°Ρ Π² ΡΠ°ΡΠΏΡΠ΅Π΄Π΅Π»Π΅Π½Π½ΠΎΠΉ ΡΡΠ΅Π΄Π΅ Ρ Π³Π°ΡΠ°Π½ΡΠΈΡΠΌΠΈ ΠΊΠΎΠ½ΡΠΈΡΡΠ΅Π½ΡΠ½ΠΎΡΡΠΈ ΠΈ ΠΎΡΠΊΠ°Π·ΠΎΡΡΡΠΎΠΉΡΠΈΠ²ΠΎΡΡΠΈ.
- Π£ΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠ΅ ΠΏΡΠΎΡΠ΅ΡΡΠ°ΠΌΠΈ: Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅, Π²ΡΠ·ΠΎΠ², Π²ΠΎΡΡΡΠ°Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ ΠΈ ΡΠ΄Π°Π»Π΅Π½ΠΈΠ΅ ΠΏΡΠΎΡΠ΅ΡΡΠΎΠ²
- ΠΠ»Π°Π½ΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ Π·Π°Π΄Π°Ρ: ΠΠΈΠ±ΠΊΠ°Ρ ΡΠΈΡΡΠ΅ΠΌΠ° ΠΏΠ»Π°Π½ΠΈΡΠΎΠ²Π°Π½ΠΈΡ Ρ ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΊΠΎΠΉ ΡΠ°ΠΉΠΌΠ΅ΡΠΎΠ² ΠΈ ΠΎΡΠ»ΠΎΠΆΠ΅Π½Π½ΠΎΠ³ΠΎ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΡ
- ΠΡΠΊΠ°Π·ΠΎΡΡΡΠΎΠΉΡΠΈΠ²ΠΎΡΡΡ: ΠΠ²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΎΠ΅ Π²ΠΎΡΡΡΠ°Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ ΠΏΠΎΡΠ»Π΅ ΡΠ±ΠΎΠ΅Π² Ρ Π½Π°ΡΡΡΠ°ΠΈΠ²Π°Π΅ΠΌΠΎΠΉ ΠΏΠΎΠ»ΠΈΡΠΈΠΊΠΎΠΉ ΠΏΠΎΠ²ΡΠΎΡΠΎΠ²
- ΠΠ°ΡΡΡΠ°Π±ΠΈΡΡΠ΅ΠΌΠΎΡΡΡ: ΠΠΎΠ΄Π΄Π΅ΡΠΆΠΊΠ° ΠΏΡΠ»ΠΎΠ² Π²ΠΎΡΠΊΠ΅ΡΠΎΠ² ΠΈ Π³ΠΎΡΠΈΠ·ΠΎΠ½ΡΠ°Π»ΡΠ½ΠΎΠ³ΠΎ ΠΌΠ°ΡΡΡΠ°Π±ΠΈΡΠΎΠ²Π°Π½ΠΈΡ
- ΠΡΡΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅: ΠΡΡΠΎΠΊΠΎΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»ΡΠ½ΠΎΠ΅ ΠΊΡΡΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ ΡΠΎΡΡΠΎΡΠ½ΠΈΡ ΠΏΡΠΎΡΠ΅ΡΡΠΎΠ² Π½Π° ΠΎΡΠ½ΠΎΠ²Π΅ Π»ΠΎΠ³ΠΈΡΠ΅ΡΠΊΠΎΠΉ ΡΠ΅ΠΏΠ»ΠΈΠΊΠ°ΡΠΈΠΈ PostgreSQL
- ΠΠΎΠ½ΠΈΡΠΎΡΠΈΠ½Π³: ΠΡΡΡΠΎΠ΅Π½Π½ΡΠ΅ ΠΌΠ΅ΡΡΠΈΠΊΠΈ Prometheus Π΄Π»Ρ Π½Π°Π±Π»ΡΠ΄Π΅Π½ΠΈΡ Π·Π° ΡΠΈΡΡΠ΅ΠΌΠΎΠΉ
- ΠΠ΄Π΅ΠΌΠΏΠΎΡΠ΅Π½ΡΠ½ΠΎΡΡΡ: ΠΠ°ΡΠΈΡΠ° ΠΎΡ Π΄ΡΠ±Π»ΠΈΡΠΎΠ²Π°Π½ΠΈΡ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΠΉ ΡΠ΅ΡΠ΅Π· ΠΊΠ»ΡΡΠΈ ΠΈΠ΄Π΅ΠΌΠΏΠΎΡΠ΅Π½ΡΠ½ΠΎΡΡΠΈ
βββββββββββββββββββ ββββββββββββββββββββββββββββββββββββββββββββ
β Client API β β Progressor β
βββββββββββββββββββ β β
β β ββββββββββββββ βββββββββββββββββββββββ β
β β β API Handlerβ β Scheduler β β
βΌ β ββββββββββββββ βββββββββββββββββββββββ β
βββββββββββββββββββ β β
β Thrift API ββββββ€ ββββββββββββββ βββββββββββββββββββββββ β
βββββββββββββββββββ β β Storage β β Worker Pool β β
β ββββββββββββββ βββββββββββββββββββββββ β
β β
β ββββββββββββββ βββββββββββββββββββββββ β
β β Cache β β Processor β β
β β (ETS) β βββββββββββββββββββββββ β
β ββββββββββββββ β
β β
β ββββββββββββββ βββββββββββββββββββββββ β
β β PostgreSQL β β Scanner β β
β ββββββββββββββ βββββββββββββββββββββββ β
β β
β ββββββββββββββ β
β β Notifier β β
β ββββββββββββββ β
ββββββββββββββββββββΌβββββββββββββββββββββββ
β
βΌ
ββββββββββββββββ
β Kafka β
ββββββββββββββββ
ΠΡΠ½ΠΎΠ²Π½ΡΠ΅ ΡΡΡΠ½ΠΎΡΡΠΈ ΡΠΈΡΡΠ΅ΠΌΡ, ΠΏΡΠ΅Π΄ΡΡΠ°Π²Π»ΡΡΡΠΈΠ΅ Π±ΠΈΠ·Π½Π΅Ρ-ΠΏΡΠΎΡΠ΅ΡΡΡ:
process_id- ΡΠ½ΠΈΠΊΠ°Π»ΡΠ½ΡΠΉ ΠΈΠ΄Π΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΎΡ ΠΏΡΠΎΡΠ΅ΡΡΠ°status- ΡΠΎΡΡΠΎΡΠ½ΠΈΠ΅ ΠΏΡΠΎΡΠ΅ΡΡΠ° (runningΠΈΠ»ΠΈerror)detail- Π΄Π΅ΡΠ°Π»ΡΠ½Π°Ρ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΡ ΠΎ ΡΠΎΡΡΠΎΡΠ½ΠΈΠΈaux_state- Π²ΡΠΏΠΎΠΌΠΎΠ³Π°ΡΠ΅Π»ΡΠ½ΠΎΠ΅ ΡΠΎΡΡΠΎΡΠ½ΠΈΠ΅ ΠΏΡΠΎΡΠ΅ΡΡΠ°metadata- ΠΌΠ΅ΡΠ°Π΄Π°Π½Π½ΡΠ΅ ΠΏΡΠΎΡΠ΅ΡΡΠ°history- ΠΈΡΡΠΎΡΠΈΡ ΡΠΎΠ±ΡΡΠΈΠΉ ΠΏΡΠΎΡΠ΅ΡΡΠ°
ΠΠ΄ΠΈΠ½ΠΈΡΡ ΡΠ°Π±ΠΎΡΡ, Π²ΡΠΏΠΎΠ»Π½ΡΠ΅ΠΌΡΠ΅ Π½Π°Π΄ ΠΏΡΠΎΡΠ΅ΡΡΠ°ΠΌΠΈ:
init- ΠΈΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΡ Π½ΠΎΠ²ΠΎΠ³ΠΎ ΠΏΡΠΎΡΠ΅ΡΡΠ°call- Π²Π½Π΅ΡΠ½ΠΈΠΉ Π²ΡΠ·ΠΎΠ² ΠΊ ΠΏΡΠΎΡΠ΅ΡΡΡrepair- Π²ΠΎΡΡΡΠ°Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ ΠΏΡΠΎΡΠ΅ΡΡΠ° ΠΏΠΎΡΠ»Π΅ ΠΎΡΠΈΠ±ΠΊΠΈtimeout- ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠ° ΡΠ°ΠΉΠΌΠ°ΡΡΠ°notify- ΡΠ²Π΅Π΄ΠΎΠΌΠ»Π΅Π½ΠΈΠ΅ ΠΎ ΡΠΎΠ±ΡΡΠΈΠΈremove- ΡΠ΄Π°Π»Π΅Π½ΠΈΠ΅ ΠΏΡΠΎΡΠ΅ΡΡΠ°
ΠΡΡΠΎΡΠΈΡ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΉ ΠΏΡΠΎΡΠ΅ΡΡΠΎΠ²:
event_id- ΠΏΠΎΡΡΠ΄ΠΊΠΎΠ²ΡΠΉ Π½ΠΎΠΌΠ΅Ρ ΡΠΎΠ±ΡΡΠΈΡtimestamp- Π²ΡΠ΅ΠΌΡ ΡΠΎΠ±ΡΡΠΈΡpayload- Π΄Π°Π½Π½ΡΠ΅ ΡΠΎΠ±ΡΡΠΈΡmetadata- ΠΌΠ΅ΡΠ°Π΄Π°Π½Π½ΡΠ΅ ΡΠΎΠ±ΡΡΠΈΡ
ΠΡΠΏΠΎΠ»Π½ΠΈΡΠ΅Π»ΠΈ Π·Π°Π΄Π°Ρ, ΡΠ°Π±ΠΎΡΠ°ΡΡΠΈΠ΅ Π² ΠΏΡΠ»Π°Ρ :
- ΠΠ±ΡΠ°Π±ΠΎΡΠΊΠ° Π·Π°Π΄Π°Ρ ΠΈΠ· ΠΎΡΠ΅ΡΠ΅Π΄Π΅ΠΉ
- ΠΠ·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡΠ²ΠΈΠ΅ Ρ ΠΏΡΠΎΡΠ΅ΡΡΠΎΡΠ°ΠΌΠΈ
- Π£ΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠ΅ ΠΆΠΈΠ·Π½Π΅Π½Π½ΡΠΌ ΡΠΈΠΊΠ»ΠΎΠΌ Π·Π°Π΄Π°Ρ
ΠΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΡ ΠΏΠΎΠΈΡΠΊΠ° Π·Π°Π΄Π°Ρ Π΄Π»Ρ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΡ:
- ΠΠΎΠΈΡΠΊ Π·Π°ΠΏΠ»Π°Π½ΠΈΡΠΎΠ²Π°Π½Π½ΡΡ Π·Π°Π΄Π°Ρ
- Π‘Π±ΠΎΡ "Π·ΠΎΠΌΠ±ΠΈ" Π·Π°Π΄Π°Ρ
- Π£ΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠ΅ ΠΎΡΠ΅ΡΠ΅Π΄ΡΠΌΠΈ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΡ
progressor:init(#{
ns => 'default/default',
id => <<"process_123">>,
args => <<"init_args">>,
context => <<"context_data">>,
idempotency_key => <<"unique_key">>
}).progressor:call(#{
ns => 'default/default',
id => <<"process_123">>,
args => <<"call_args">>,
context => <<"context_data">>,
idempotency_key => <<"call_key">>
}).progressor:repair(#{
ns => 'default/default',
id => <<"process_123">>,
args => <<"repair_args">>,
context => <<"context_data">>
}).progressor:get(#{
ns => 'default/default',
id => <<"process_123">>,
range => #{
offset => 0,
limit => 100,
direction => forward
}
}).progressor:put(#{
ns => 'default/default',
id => <<"process_123">>,
args => #{
process => #{
process_id => <<"process_123">>,
status => <<"running">>,
aux_state => <<"state_data">>
},
action => #{set_timer => 1640995200}
}
}).{progressor, [
{defaults, #{
storage => #{
client => prg_pg_backend,
options => #{
pool => default_pool,
scan_pool => default_scan_pool,
front_pool => default_front_pool,
cache => db_ref
}
},
retry_policy => #{
initial_timeout => 3, % ΡΠ΅ΠΊΡΠ½Π΄Ρ
backoff_coefficient => 1.2,
max_timeout => 180, % ΡΠ΅ΠΊΡΠ½Π΄Ρ
max_attempts => 2,
non_retryable_errors => [
some_reason,
<<"Error message">>
]
},
task_scan_timeout => 10, % ΡΠ΅ΠΊΡΠ½Π΄Ρ
worker_pool_size => 200,
process_step_timeout => 30 % ΡΠ΅ΠΊΡΠ½Π΄Ρ
}},
{namespaces, #{
'default/default' => #{
processor => #{
client => custom_processor,
options => #{}
},
notifier => #{
client => default_kafka_client,
options => #{
topic => <<"events_topic">>,
lifecycle_topic => <<"lifecycle_topic">>
}
}
}
}}
]}{epg_connector, [
{databases, #{
progressor_db => #{
host => "postgres",
port => 5432,
database => "progressor_db",
username => "progressor",
password => "progressor"
}
}},
{pools, #{
default_pool => #{
database => progressor_db,
size => 100
},
default_scan_pool => #{
database => progressor_db,
size => 1
},
default_front_pool => #{
database => progressor_db,
size => 10
}
}}
]}{brod, [
{clients, [
{default_kafka_client, [
{endpoints, [{"kafka1", 9092}, {"kafka2", 9092}]},
{auto_start_producers, true},
{default_producer_config, []}
]}
]}
]}ΠΡΠΎΡΠ΅ΡΡΠΎΡ ΠΎΠΏΡΠ΅Π΄Π΅Π»ΡΠ΅Ρ Π±ΠΈΠ·Π½Π΅Ρ-Π»ΠΎΠ³ΠΈΠΊΡ ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠΈ ΠΏΡΠΎΡΠ΅ΡΡΠΎΠ²:
-module(my_processor).
-export([process/3]).
process({TaskType, Args, Process}, Options, Context) ->
#{
process_id := ProcessId,
status := Status,
aux_state := AuxState,
history := History
} = Process,
% ΠΠΈΠ·Π½Π΅Ρ-Π»ΠΎΠ³ΠΈΠΊΠ° ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠΈ
NewEvent = #{
event_id => length(History) + 1,
timestamp => erlang:system_time(second),
metadata => #{<<"format_version">> => 1},
payload => create_payload(TaskType, Args)
},
% Π Π΅Π·ΡΠ»ΡΡΠ°Ρ ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠΈ
Result = #{
events => [NewEvent],
aux_state => update_aux_state(AuxState, TaskType),
metadata => #{<<"last_update">> => erlang:system_time(second)},
response => {ok, <<"success">>}
},
% ΠΠΏΡΠΈΠΎΠ½Π°Π»ΡΠ½ΠΎ ΡΡΡΠ°Π½ΠΎΠ²ΠΈΡΡ ΡΠ°ΠΉΠΌΠ΅Ρ
case should_set_timer(Process, TaskType) of
true ->
TimerTime = erlang:system_time(second) + 60,
{ok, Result#{action => #{set_timer => TimerTime}}};
false ->
{ok, Result}
end.% ΠΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΡ ΠΏΡΠΎΡΠ΅ΡΡΠ°
{ok, ok} = progressor:init(#{
ns => 'default/default',
id => <<"timer_process">>,
args => <<"init">>
}),
% ΠΡΠΎΡΠ΅ΡΡΠΎΡ ΡΡΡΠ°Π½Π°Π²Π»ΠΈΠ²Π°Π΅Ρ ΡΠ°ΠΉΠΌΠ΅Ρ Π½Π° 60 ΡΠ΅ΠΊΡΠ½Π΄
% Π§Π΅ΡΠ΅Π· 60 ΡΠ΅ΠΊΡΠ½Π΄ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΈ Π²ΡΠΏΠΎΠ»Π½ΠΈΡΡΡ timeout Π·Π°Π΄Π°ΡΠ°
% ΠΠΎΠ»ΡΡΠ΅Π½ΠΈΠ΅ ΡΠΎΡΡΠΎΡΠ½ΠΈΡ
{ok, Process} = progressor:get(#{
ns => 'default/default',
id => <<"timer_process">>
}).% ΠΡΠ·ΠΎΠ² ΠΏΡΠΎΡΠ΅ΡΡΠ° Ρ Π²Π½Π΅ΡΠ½ΠΈΠΌΠΈ Π΄Π°Π½Π½ΡΠΌΠΈ
{ok, Response} = progressor:call(#{
ns => 'default/default',
id => <<"active_process">>,
args => <<"external_data">>,
idempotency_key => <<"call_123">>
}).% ΠΠΎΡΡΡΠ°Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ ΠΏΡΠΎΡΠ΅ΡΡΠ° Π² ΡΠΎΡΡΠΎΡΠ½ΠΈΠΈ error
{ok, ok} = progressor:repair(#{
ns => 'default/default',
id => <<"failed_process">>,
args => <<"repair_data">>
}).Π‘ΠΈΡΡΠ΅ΠΌΠ° ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²Π»ΡΠ΅Ρ ΡΠ»Π΅Π΄ΡΡΡΠΈΠ΅ ΠΌΠ΅ΡΡΠΈΠΊΠΈ Prometheus:
progressor_calls_scanning_duration_ms- ΠΡΠ΅ΠΌΡ ΡΠΊΠ°Π½ΠΈΡΠΎΠ²Π°Π½ΠΈΡ Π²ΡΠ·ΠΎΠ²ΠΎΠ²progressor_timers_scanning_duration_ms- ΠΡΠ΅ΠΌΡ ΡΠΊΠ°Π½ΠΈΡΠΎΠ²Π°Π½ΠΈΡ ΡΠ°ΠΉΠΌΠ΅ΡΠΎΠ²progressor_zombie_collection_duration_ms- ΠΡΠ΅ΠΌΡ ΡΠ±ΠΎΡΠΊΠΈ Π·ΠΎΠΌΠ±ΠΈ-Π·Π°Π΄Π°Ρprogressor_request_preparing_duration_ms- ΠΡΠ΅ΠΌΡ ΠΏΠΎΠ΄Π³ΠΎΡΠΎΠ²ΠΊΠΈ Π·Π°ΠΏΡΠΎΡΠΎΠ²progressor_task_processing_duration_ms- ΠΡΠ΅ΠΌΡ ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠΈ Π·Π°Π΄Π°Ρprogressor_task_completion_duration_ms- ΠΡΠ΅ΠΌΡ Π·Π°Π²Π΅ΡΡΠ΅Π½ΠΈΡ Π·Π°Π΄Π°Ρprogressor_process_removing_duration_ms- ΠΡΠ΅ΠΌΡ ΡΠ΄Π°Π»Π΅Π½ΠΈΡ ΠΏΡΠΎΡΠ΅ΡΡΠΎΠ²progressor_notification_duration_ms- ΠΡΠ΅ΠΌΡ ΠΎΡΠΏΡΠ°Π²ΠΊΠΈ ΡΠ²Π΅Π΄ΠΎΠΌΠ»Π΅Π½ΠΈΠΉ
% ΠΡΠΎΠ²Π΅ΡΠΊΠ° ΡΠΎΡΡΠΎΡΠ½ΠΈΡ namespace
{Status, Details} = progressor:health_check(['default/default']).
% Status: passing | critical# Π‘Π±ΠΎΡΠΊΠ° ΠΎΠ±ΡΠ°Π·Π°
docker build -f Dockerfile.dev -t progressor:dev .
# ΠΠ°ΠΏΡΡΠΊ Ρ docker-compose
docker-compose up -d# ΠΠΎΠΌΠΏΠΈΠ»ΡΡΠΈΡ
make compile
# Π’Π΅ΡΡΡ
make test
# Π€ΠΎΡΠΌΠ°ΡΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ ΠΊΠΎΠ΄Π°
make fmt
# Π‘ΡΠ°ΡΠΈΡΠ΅ΡΠΊΠΈΠΉ Π°Π½Π°Π»ΠΈΠ·
make dialyzerΠ‘ΠΈΡΡΠ΅ΠΌΠ° ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΈΠ²Π°Π΅Ρ Π³ΠΈΠ±ΠΊΡΡ Π½Π°ΡΡΡΠΎΠΉΠΊΡ ΠΏΠΎΠ²ΡΠΎΡΠΎΠ² ΠΏΡΠΈ ΠΎΡΠΈΠ±ΠΊΠ°Ρ :
retry_policy => #{
initial_timeout => 5, % ΠΠ°ΡΠ°Π»ΡΠ½Π°Ρ Π·Π°Π΄Π΅ΡΠΆΠΊΠ° (ΡΠ΅ΠΊ)
backoff_coefficient => 2.0, % ΠΠΎΡΡΡΠΈΡΠΈΠ΅Π½Ρ ΡΠ²Π΅Π»ΠΈΡΠ΅Π½ΠΈΡ Π·Π°Π΄Π΅ΡΠΆΠΊΠΈ
max_timeout => 300, % ΠΠ°ΠΊΡΠΈΠΌΠ°Π»ΡΠ½Π°Ρ Π·Π°Π΄Π΅ΡΠΆΠΊΠ° (ΡΠ΅ΠΊ)
max_attempts => 5, % ΠΠ°ΠΊΡΠΈΠΌΠ°Π»ΡΠ½ΠΎΠ΅ ΠΊΠΎΠ»ΠΈΡΠ΅ΡΡΠ²ΠΎ ΠΏΠΎΠΏΡΡΠΎΠΊ
non_retryable_errors => [ % ΠΡΠΈΠ±ΠΊΠΈ Π±Π΅Π· ΠΏΠΎΠ²ΡΠΎΡΠΎΠ²
validation_failed,
<<"Invalid input">>
]
}- ΠΡΠ΅Π³Π΄Π° ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠΉΡΠ΅ ΠΊΠ»ΡΡΠΈ ΠΈΠ΄Π΅ΠΌΠΏΠΎΡΠ΅Π½ΡΠ½ΠΎΡΡΠΈ Π΄Π»Ρ ΠΊΡΠΈΡΠΈΡΠ½ΡΡ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΠΉ
- ΠΠ»ΡΡΠΈ Π΄ΠΎΠ»ΠΆΠ½Ρ Π±ΡΡΡ ΡΠ½ΠΈΠΊΠ°Π»ΡΠ½ΡΠΌΠΈ Π² ΡΠ°ΠΌΠΊΠ°Ρ namespace
- ΠΠ°ΡΡΡΠΎΠΉΡΠ΅ Π°Π»Π΅ΡΡΡ Π½Π° ΠΌΠ΅ΡΡΠΈΠΊΠΈ Π΄Π»ΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΠΈ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΠΉ
- ΠΡΡΠ»Π΅ΠΆΠΈΠ²Π°ΠΉΡΠ΅ ΠΊΠΎΠ»ΠΈΡΠ΅ΡΡΠ²ΠΎ Π·ΠΎΠΌΠ±ΠΈ-Π·Π°Π΄Π°Ρ
- ΠΠΎΠ½ΠΈΡΠΎΡΡΡΠ΅ ΡΠΎΡΡΠΎΡΠ½ΠΈΠ΅ ΠΏΡΠ»ΠΎΠ² ΠΏΠΎΠ΄ΠΊΠ»ΡΡΠ΅Π½ΠΈΠΉ ΠΊ ΠΠ
- ΠΠ°ΡΡΡΠΎΠΉΡΠ΅ ΡΠ°Π·ΠΌΠ΅ΡΡ ΠΏΡΠ»ΠΎΠ² Π²ΠΎΡΠΊΠ΅ΡΠΎΠ² ΠΏΠΎΠ΄ Π½Π°Π³ΡΡΠ·ΠΊΡ
- ΠΠΏΡΠΈΠΌΠΈΠ·ΠΈΡΡΠΉΡΠ΅ ΡΠ°Π·ΠΌΠ΅ΡΡ ΠΏΡΠ»ΠΎΠ² ΠΏΠΎΠ΄ΠΊΠ»ΡΡΠ΅Π½ΠΈΠΉ ΠΊ PostgreSQL
- ΠΡΠΏΠΎΠ»ΡΠ·ΡΠΉΡΠ΅ ΠΏΠ°ΡΡΠΈΡΠΈΠΎΠ½ΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ ΡΠ°Π±Π»ΠΈΡ Π΄Π»Ρ Π±ΠΎΠ»ΡΡΠΈΡ ΠΎΠ±ΡΠ΅ΠΌΠΎΠ² Π΄Π°Π½Π½ΡΡ
- ΠΠ°ΡΡΡΠΎΠΉΡΠ΅ ΡΠ΅ΠΏΠ»ΠΈΠΊΠ°ΡΠΈΡ PostgreSQL
- ΠΡΠΏΠΎΠ»ΡΠ·ΡΠΉΡΠ΅ ΠΊΠ»Π°ΡΡΠ΅Ρ Kafka Π΄Π»Ρ ΡΠ²Π΅Π΄ΠΎΠΌΠ»Π΅Π½ΠΈΠΉ
- Π Π΅Π³ΡΠ»ΡΡΠ½ΠΎ ΡΠΎΠ·Π΄Π°Π²Π°ΠΉΡΠ΅ ΡΠ΅Π·Π΅ΡΠ²Π½ΡΠ΅ ΠΊΠΎΠΏΠΈΠΈ Π΄Π°Π½Π½ΡΡ
Progressor ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΈΠ²Π°Π΅Ρ ΠΊΡΡΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ ΡΠΎΡΡΠΎΡΠ½ΠΈΡ ΠΏΡΠΎΡΠ΅ΡΡΠΎΠ² Ρ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅ΠΌ Π»ΠΎΠ³ΠΈΡΠ΅ΡΠΊΠΎΠΉ ΡΠ΅ΠΏΠ»ΠΈΠΊΠ°ΡΠΈΠΈ PostgreSQL. ΠΡΡ ΡΠ΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Π½ Π½Π° Π±Π°Π·Π΅ ETS ΡΠ°Π±Π»ΠΈΡ.
- ΠΠΎΠ³ΠΈΡΠ΅ΡΠΊΠ°Ρ ΡΠ΅ΠΏΠ»ΠΈΠΊΠ°ΡΠΈΡ: ΠΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΡΡΡ Π²ΡΡΡΠΎΠ΅Π½Π½Π°Ρ Π»ΠΎΠ³ΠΈΡΠ΅ΡΠΊΠ°Ρ ΡΠ΅ΠΏΠ»ΠΈΠΊΠ°ΡΠΈΡ PostgreSQL Π΄Π»Ρ ΠΎΡΡΠ»Π΅ΠΆΠΈΠ²Π°Π½ΠΈΡ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΉ Π² ΡΠ°Π±Π»ΠΈΡΠ°Ρ ΠΏΡΠΎΡΠ΅ΡΡΠΎΠ² ΠΈ ΡΠΎΠ±ΡΡΠΈΠΉ
- WAL Reader: ΠΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ
epg_wal_readerΡΠΈΡΠ°Π΅Ρ Write-Ahead Log (WAL) ΠΈ ΠΏΠ΅ΡΠ΅Π΄Π°Π΅Ρ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΡ Π² ΠΊΡΡ - ETS Ρ ΡΠ°Π½ΠΈΠ»ΠΈΡΠ΅: ΠΠ°Π½Π½ΡΠ΅ ΠΊΡΡΠΈΡΡΡΡΡΡ Π² Π±ΡΡΡΡΡΡ ETS ΡΠ°Π±Π»ΠΈΡΠ°Ρ Π² ΠΏΠ°ΠΌΡΡΠΈ Erlang
- ΠΠ²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠ°Ρ ΠΎΡΠΈΡΡΠΊΠ°: ΠΠ΅Π°ΠΊΡΠΈΠ²Π½ΡΠ΅ ΠΏΡΠΎΡΠ΅ΡΡΡ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΈ ΡΠ΄Π°Π»ΡΡΡΡΡ ΠΈΠ· ΠΊΡΡΠ° ΠΏΠΎ ΡΠ°ΠΉΠΌΠ°ΡΡΡ
{namespaces, #{
'cached/namespace' => #{
storage => #{
client => prg_pg_backend,
options => #{
pool => default_pool,
cache => progressor_db % Π‘ΡΡΠ»ΠΊΠ° Π½Π° Π±Π°Π·Ρ Π΄Π°Π½Π½ΡΡ
}
},
processor => #{
client => my_processor,
options => #{}
}
}
}}{post_init_hooks, [
{prg_pg_cache, start, [
#{
progressor_db => {
['cached/namespace'], % Π‘ΠΏΠΈΡΠΎΠΊ ΠΊΡΡΠΈΡΡΠ΅ΠΌΡΡ
namespace
"progressor" % ΠΠΌΡ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ Π΄Π»Ρ replication slot
}
}
]}
]}% Π’Π°ΠΉΠΌΠ°ΡΡ ΠΏΠ΅ΡΠ΅ΠΏΠΎΠ΄ΠΊΠ»ΡΡΠ΅Π½ΠΈΡ ΠΊ ΡΠ΅ΠΏΠ»ΠΈΠΊΠ°ΡΠΈΠΈ (ΠΏΠΎ ΡΠΌΠΎΠ»ΡΠ°Π½ΠΈΡ 5000 ΠΌΡ)
{cache_reconnect_timeout, 5000},
% Π’Π°ΠΉΠΌΠ°ΡΡ ΠΎΡΠΈΡΡΠΊΠΈ Π½Π΅Π°ΠΊΡΠΈΠ²Π½ΡΡ
ΠΏΡΠΎΡΠ΅ΡΡΠΎΠ² (ΠΏΠΎ ΡΠΌΠΎΠ»ΡΠ°Π½ΠΈΡ 300000 ΠΌΡ = 5 ΠΌΠΈΠ½)
{cache_cleanup_timeout, 300000}- ΠΡΡΠΎΠΊΠ°Ρ ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΡ: ΠΠΏΠ΅ΡΠ°ΡΠΈΠΈ ΡΡΠ΅Π½ΠΈΡ Π²ΡΠΏΠΎΠ»Π½ΡΡΡΡΡ ΠΈΠ· ΠΏΠ°ΠΌΡΡΠΈ Π±Π΅Π· ΠΎΠ±ΡΠ°ΡΠ΅Π½ΠΈΡ ΠΊ ΠΠ
- ΠΠ²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠ°Ρ ΡΠΈΠ½Ρ ΡΠΎΠ½ΠΈΠ·Π°ΡΠΈΡ: ΠΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΡ Π² ΠΠ ΠΎΡΡΠ°ΠΆΠ°ΡΡΡΡ Π² ΠΊΡΡΠ΅ Ρ Π½Π΅Π·Π½Π°ΡΠΈΡΠ΅Π»ΡΠ½ΠΎΠΉ Π·Π°Π΄Π΅ΡΠΆΠΊΠΎΠΉ (Π·Π°Π΄Π΅ΡΠΆΠΊΠ° ΡΠ΅ΠΏΠ»ΠΈΠΊΠ°ΡΠΈΠΈ)
- ΠΡΠΊΠ°Π·ΠΎΡΡΡΠΎΠΉΡΠΈΠ²ΠΎΡΡΡ: ΠΡΠΈ ΠΏΠΎΡΠ΅ΡΠ΅ ΡΠΎΠ΅Π΄ΠΈΠ½Π΅Π½ΠΈΡ Ρ ΡΠ΅ΠΏΠ»ΠΈΠΊΠ°ΡΠΈΠ΅ΠΉ ΠΊΡΡ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΈ ΠΏΠ΅ΡΠ΅ΠΏΠΎΠ΄ΠΊΠ»ΡΡΠ°Π΅ΡΡΡ (ΠΏΡΠΈ ΠΏΠΎΡΠ΅ΡΠ΅ ΡΠΎΠ΅Π΄ΠΈΠ½Π΅Π½ΠΈΡ ΠΊΡΡ ΠΎΡΠΈΡΠ°Π΅ΡΡΡ Π΄ΠΎ Π²ΠΎΡΡΡΠ°Π½ΠΎΠ²Π»Π΅Π½ΠΈΡ ΡΠΎΠ΅Π΄ΠΈΠ½Π΅Π½ΠΈΡ)
- Π£ΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠ΅ ΠΏΠ°ΠΌΡΡΡΡ: ΠΠ΅Π°ΠΊΡΠΈΠ²Π½ΡΠ΅ ΠΏΡΠΎΡΠ΅ΡΡΡ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΈ ΡΠ΄Π°Π»ΡΡΡΡΡ ΠΈΠ· ΠΊΡΡΠ°
ΠΠ»Ρ ΡΠ°Π±ΠΎΡΡ ΠΊΡΡΠΈΡΠΎΠ²Π°Π½ΠΈΡ Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΎ:
-
ΠΠΎΠ³ΠΈΡΠ΅ΡΠΊΠ°Ρ ΡΠ΅ΠΏΠ»ΠΈΠΊΠ°ΡΠΈΡ Π²ΠΊΠ»ΡΡΠ΅Π½Π°:
-- Π postgresql.conf wal_level = logical max_replication_slots = 10 max_wal_senders = 10
-
ΠΡΠ°Π²Π° ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Ρ:
-- ΠΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Ρ Π΄ΠΎΠ»ΠΆΠ΅Π½ ΠΈΠΌΠ΅ΡΡ ΠΏΡΠ°Π²Π° Π½Π° ΡΠΎΠ·Π΄Π°Π½ΠΈΠ΅ replication slot ALTER ROLE progressor_user REPLICATION; -
Publication ΡΠΎΠ·Π΄Π°Π΅ΡΡΡ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΈ Π΄Π»Ρ ΡΠ°Π±Π»ΠΈΡ ΠΏΡΠΎΡΠ΅ΡΡΠΎΠ² ΠΈ ΡΠΎΠ±ΡΡΠΈΠΉ ΠΊΡΡΠΈΡΡΠ΅ΠΌΡΡ namespace
NOT IMPLEMENTED (TODO cache_hit_counter)
Progressor ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²Π»ΡΠ΅Ρ Π½Π°Π΄Π΅ΠΆΠ½ΡΡ ΠΏΠ»Π°ΡΡΠΎΡΠΌΡ Π΄Π»Ρ ΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΡ Π΄ΠΎΠ»Π³ΠΎΠΆΠΈΠ²ΡΡΠΈΠΌΠΈ ΠΏΡΠΎΡΠ΅ΡΡΠ°ΠΌΠΈ Ρ Π³Π°ΡΠ°Π½ΡΠΈΡΠΌΠΈ ΠΊΠΎΠ½ΡΠΈΡΡΠ΅Π½ΡΠ½ΠΎΡΡΠΈ, ΠΎΡΠΊΠ°Π·ΠΎΡΡΡΠΎΠΉΡΠΈΠ²ΠΎΡΡΠΈ ΠΈ ΠΌΠ°ΡΡΡΠ°Π±ΠΈΡΡΠ΅ΠΌΠΎΡΡΠΈ. ΠΡΡΡΠΎΠ΅Π½Π½ΠΎΠ΅ ΠΊΡΡΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ Π½Π° ΠΎΡΠ½ΠΎΠ²Π΅ Π»ΠΎΠ³ΠΈΡΠ΅ΡΠΊΠΎΠΉ ΡΠ΅ΠΏΠ»ΠΈΠΊΠ°ΡΠΈΠΈ PostgreSQL ΠΎΠ±Π΅ΡΠΏΠ΅ΡΠΈΠ²Π°Π΅Ρ Π²ΡΡΠΎΠΊΡΡ ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΡ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΠΉ ΡΡΠ΅Π½ΠΈΡ ΠΏΡΠΈ ΡΠΎΡ ΡΠ°Π½Π΅Π½ΠΈΠΈ Π°ΠΊΡΡΠ°Π»ΡΠ½ΠΎΡΡΠΈ Π΄Π°Π½Π½ΡΡ . Π‘ΠΈΡΡΠ΅ΠΌΠ° ΠΏΠΎΠ΄Ρ ΠΎΠ΄ΠΈΡ Π΄Π»Ρ ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΠΈ ΡΠ»ΠΎΠΆΠ½ΡΡ Π±ΠΈΠ·Π½Π΅Ρ-ΠΏΡΠΎΡΠ΅ΡΡΠΎΠ², ΡΡΠ΅Π±ΡΡΡΠΈΡ Π½Π°Π΄Π΅ΠΆΠ½ΠΎΠ³ΠΎ ΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΡ ΡΠΎΡΡΠΎΡΠ½ΠΈΠ΅ΠΌ ΠΈ ΠΏΠ»Π°Π½ΠΈΡΠΎΠ²Π°Π½ΠΈΡ Π·Π°Π΄Π°Ρ.