P2C-12: New limiter proto (#2)

* new limiter proto

* added clock

* added configurator service

* added limit context

* added id and desc to configuration

* added requested changes

* refactored limit config api

* added timestamp to config struct

* moved operation_timestamp from change to context

* added ForbiddenOperationAmount exception

* added shard size to config

* added lim range

* fixed account id

* added limit config and new limit context

* fixed

* added currency to config

* updated configurator

* removed cash from limiter limit struct

* added op type to context

* removed entity

* added context type to config

* added currency to limit range

* changed to optional for op
This commit is contained in:
Артем 2021-04-29 12:00:46 +03:00 committed by GitHub
parent e0b008c58c
commit 84cc6b7355
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 464 additions and 235 deletions

21
Jenkinsfile vendored
View File

@ -10,28 +10,15 @@ build('limiter-proto', 'docker-host') {
runStage('load pipeline') { runStage('load pipeline') {
env.JENKINS_LIB = "build_utils/jenkins_lib" env.JENKINS_LIB = "build_utils/jenkins_lib"
pipeDefault = load("${env.JENKINS_LIB}/pipeDefault.groovy") pipeDefault = load("${env.JENKINS_LIB}/pipeDefault.groovy")
pipeJavaProto = load("${env.JENKINS_LIB}/pipeJavaProto.groovy")
gitUtils = load("${env.JENKINS_LIB}/gitUtils.groovy") gitUtils = load("${env.JENKINS_LIB}/gitUtils.groovy")
} }
pipeDefault() { pipeDefault() {
runStage('compile') { runStage('compile') {
withGithubPrivkey { sh "make wc_compile"
sh "make submodules"
sh "make wc_compile"
}
} }
env.skipSonar = 'true'
// Java pipeJavaProto()
runStage('Execute build container') {
withCredentials([[$class: 'FileBinding', credentialsId: 'java-maven-settings.xml', variable: 'SETTINGS_XML']]) {
if (env.BRANCH_NAME == 'master' || env.BRANCH_NAME.startsWith('epic/')) {
sh 'make SETTINGS_XML=${SETTINGS_XML} BRANCH_NAME=${BRANCH_NAME} wc_java.deploy'
} else {
sh 'make SETTINGS_XML=${SETTINGS_XML} wc_java.compile'
}
}
}
} }
} }

View File

@ -7,13 +7,12 @@ UTILS_PATH := build_utils
TEMPLATES_PATH := . TEMPLATES_PATH := .
# Name of the service # Name of the service
SERVICE_NAME := limiter_proto SERVICE_NAME := limiter-proto
# Build image tag to be used # Build image tag to be used
BUILD_IMAGE_TAG := eee42f2ca018c313190bc350fe47d4dea70b6d27 BUILD_IMAGE_TAG := b04c5291d101132e53e578d96e1628d2e6dab0c0
CALL_ANYWHERE := \ CALL_ANYWHERE := \
all submodules rebar-update compile clean distclean \ all submodules compile clean distclean
java.compile java.deploy
CALL_W_CONTAINER := $(CALL_ANYWHERE) CALL_W_CONTAINER := $(CALL_ANYWHERE)
@ -30,10 +29,7 @@ $(SUBTARGETS): %/.git: %
submodules: $(SUBTARGETS) submodules: $(SUBTARGETS)
rebar-update: compile:
$(REBAR) update
compile: submodules
$(REBAR) compile $(REBAR) compile
clean: clean:
@ -41,43 +37,6 @@ clean:
distclean: distclean:
$(REBAR) clean -a $(REBAR) clean -a
rm -rfv _build _builds _cache _steps _temp rm -rfv _build
# Java include $(UTILS_PATH)/make_lib/java_proto.mk
ifdef SETTINGS_XML
DOCKER_RUN_OPTS = -v $(SETTINGS_XML):$(SETTINGS_XML)
DOCKER_RUN_OPTS += -e SETTINGS_XML=$(SETTINGS_XML)
endif
ifdef LOCAL_BUILD
DOCKER_RUN_OPTS += -v $$HOME/.m2:/home/$(UNAME)/.m2:rw
endif
COMMIT_HASH := $(shell git --no-pager log -1 --pretty=format:"%h")
NUMBER_COMMITS := $(shell git rev-list --count HEAD)
JAVA_PKG_VERSION := 1.$(NUMBER_COMMITS)-$(COMMIT_HASH)
ifdef BRANCH_NAME
ifeq "$(findstring epic,$(BRANCH_NAME))" "epic"
JAVA_PKG_VERSION := $(JAVA_PKG_VERSION)-epic
endif
endif
MVN = mvn -s $(SETTINGS_XML) -Dpath_to_thrift="$(THRIFT)" -Dcommit.number="$(NUMBER_COMMITS)"
java.compile: java.settings
$(MVN) compile
java.deploy: java.settings
$(MVN) versions:set versions:commit -DnewVersion="$(JAVA_PKG_VERSION)" && \
$(MVN) deploy
java.install: java.settings
$(MVN) clean && \
$(MVN) versions:set versions:commit -DnewVersion="$(JAVA_PKG_VERSION)" && \
$(MVN) install
java.settings:
$(if $(SETTINGS_XML),, echo "SETTINGS_XML not defined"; exit 1)

@ -1 +1 @@
Subproject commit b9b18f3ee375aa5fd105daf57189ac242c40f572 Subproject commit e1318727d4d0c3e48f5122bf3197158b6695f50e

89
proto/base.thrift Normal file
View File

@ -0,0 +1,89 @@
namespace java com.rbkmoney.limiter.base
namespace erlang limiter_base
/**
* Отметка во времени согласно RFC 3339.
*
* Строка должна содержать дату и время в UTC в следующем формате:
* `2016-03-22T06:12:27Z`.
*/
typedef string Timestamp
/** Идентификатор объекта */
typedef string ID
typedef i32 ObjectID
/** Идентификатор аккаунта */
typedef i64 AccountID
/** Идентификатор некоторого события */
typedef i64 EventID
struct EventRange {
1: optional EventID after
2: optional i32 limit
}
/** ISO 4217 */
typedef string CurrencySymbolicCode
/** Сумма в минимальных денежных единицах. */
typedef i64 Amount
/** Значение ассоциации */
typedef string Tag
/** Внешний идентификатор (идентификатор в системе клиента) для сущностей системы. */
typedef ID ExternalID
typedef i64 DataRevision
typedef i64 PartyRevision
/** Непрозрачный для участника общения набор данных */
typedef binary Opaque
/**
* Идентификатор валюты
*
* Украдено из https://github.com/rbkmoney/damsel/blob/8235b6f6/proto/domain.thrift#L912
*/
struct CurrencyRef { 1: required CurrencySymbolicCode symbolic_code }
/**
* Объём денежных средств
*
* Украдено из https://github.com/rbkmoney/damsel/blob/8235b6f6/proto/domain.thrift#L70
*/
struct Cash {
1: required Amount amount
2: required CurrencyRef currency
}
struct CashRange {
1: required CashBound upper
2: required CashBound lower
}
union CashBound {
1: Cash inclusive
2: Cash exclusive
}
struct AmountRange {
1: required AmountBound upper
2: required AmountBound lower
}
union AmountBound {
1: Amount inclusive
2: Amount exclusive
}
/**
* Исключение, сигнализирующее о непригодных с точки зрения бизнес-логики входных данных
*/
exception InvalidRequest {
/** Список пригодных для восприятия человеком ошибок во входных данных */
1: required list<string> errors
}

36
proto/configurator.thrift Normal file
View File

@ -0,0 +1,36 @@
include "base.thrift"
include "limiter.thrift"
include "limiter_config.thrift"
namespace java com.rbkmoney.limiter.configurator
namespace erlang limiter_cfg
typedef base.ID LimitName
typedef limiter_config.LimitConfigID LimitConfigID
typedef limiter_config.ShardSize ShardSize
typedef limiter_config.LimitConfig LimitConfig
typedef limiter_config.LimitBodyType LimitBodyType
struct LimitCreateParams {
1: required LimitConfigID id
2: required base.Timestamp started_at
/** Идентификатор набора настроек создаваемого лимата, в будущем идентификатор заменит структура конфигурации */
3: optional LimitName name
4: optional string description
5: optional LimitBodyType body_type
}
exception LimitConfigNameNotFound {}
exception LimitConfigNotFound {}
service Configurator {
LimitConfig Create(1: LimitCreateParams params) throws (
1: LimitConfigNameNotFound e1,
2: base.InvalidRequest e2
)
LimitConfig Get(1: LimitConfigID id) throws (
1: LimitConfigNotFound e1,
2: base.InvalidRequest e2
)
}

View File

@ -1,165 +1,63 @@
include "base.thrift"
include "limiter_context.thrift"
namespace java com.rbkmoney.limiter namespace java com.rbkmoney.limiter
namespace erlang limiter namespace erlang limiter
include "proto/shumpune.thrift" typedef base.ID LimitChangeID
include "proto/base.thrift" typedef base.ID LimitID
typedef base.ID PartyID
typedef string LimitID typedef base.ID ShopID
typedef string PlanID typedef base.ID WalletID
typedef i64 BatchID typedef base.ID IdentityID
typedef i64 AccountID typedef limiter_context.LimitContext LimitContext
typedef string LimitRef
typedef i64 DomainRevision
typedef shumpune.Clock Clock
typedef shumpune.Balance Balance
typedef base.InvalidRequest InvalidRequest
/** /**
* Описывает типы лимитов: * https://en.wikipedia.org/wiki/Vector_clock
* cash - валютный лимит - ассоциирован с изменением сумм в какой-либо валюте **/
* count - счетный лимит - ассоциирован с количеством каких-либо операций в системе struct VectorClock {
*/ 1: required base.Opaque state
enum LimitType {
cash
count
} }
/** /**
* Структура данных, описывающая свойства сублимита: * Структура, позволяющая установить причинно-следственную связь операций внутри сервиса
* account_id -идентификатор аккаунта ассоциированного с временным действием сублимита **/
* time_range - время действия сублимита union Clock {
*/ 1: VectorClock vector
struct Sublimit {
1: required AccountID account_id
2: required LimitTimeRange time_range
} }
/**
* Структура данных, описывающая свойства лимита:
* id -идентификатор машины лимита
* ref - идентификатор лимита в domain конфигурации
* domain_revision - ревизия конфигурации
* type - тип лимита
* sublimits - сублимиты лимита
* description - описание (неизменяемо после создания лимита)
*/
struct Limit { struct Limit {
1: required LimitID id 1: required LimitID id
2: required LimitRef ref 2: required base.Amount amount
3: required DomainRevision domain_revision 3: optional base.Timestamp creation_time
4: required LimitType type 4: optional string description
5: required list<Sublimit> sublimits
6: optional string description
} }
/** struct LimitChange {
* Описывает одно изменение лимита в системе, может быть следующих типов: 1: required LimitID id
* cash - изменение валютного лимита 2: required LimitChangeID change_id
* count - изменение счетного лимита
*/
union LimitUnit {
1: LimitUnitCash cash
2: LimitUnitCount count
} }
struct LimitUnitCash { exception LimitNotFound {}
exception LimitChangeNotFound {}
exception ForbiddenOperationAmount {
1: required base.Amount amount 1: required base.Amount amount
2: required base.CurrencySymbolicCode currency_sym_code 2: required base.AmountRange allowed_range
} }
struct LimitUnitCount { service Limiter {
1: required base.Amount amount Limit Get(1: LimitID id, 2: Clock clock, 3: LimitContext context) throws (
} 1: LimitNotFound e1,
2: base.InvalidRequest e2
/** )
* Описывает батч - набор изменений лимита, служит единицей атомарности операций в системе: Clock Hold(1: LimitChange change, 2: Clock clock, 3: LimitContext context) throws (
* id - идентификатор набора, уникален в пределах плана 1: LimitNotFound e1,
* units - набор изменений лимита 3: base.InvalidRequest e2
*/ )
struct LimitBatch { Clock Commit(1: LimitChange change, 2: Clock clock, 3: LimitContext context) throws (
1: required BatchID id 1: LimitNotFound e1,
2: required list<LimitUnit> units 2: LimitChangeNotFound e2,
} 3: base.InvalidRequest e3,
4: ForbiddenOperationAmount e4
/** )
* План состоит из набора батчей, который можно пополнить, подтвердить или отменить:
* id - идентификатор плана, уникален в рамках системы
* batch_list - набор батчей, связанный с данным планом
*/
struct LimitPlan {
1: required PlanID id
2: required list<LimitBatch> batch_list
}
/**
* Описывает параметры создания лимита:
* ref - идентификатор лимита в domain конфигурации
* domain_revision - ревизия конфигурации
* create_time - время старта нового временного интервала лимита
*/
struct LimitCreateParams {
1: required LimitRef ref
2: required DomainRevision domain_revision
3: required base.Timestamp create_time
}
/**
* Описывает единицу изменения плана:
* id - id плана, к которому применяется данное изменение
* batch - набор изменений, который нужно добавить в план
* create_params - если такого лимита нет или срок дейтсвия сублимита истек, то эти параметры
* будут использованы чтобы проинициализировать новый лимит/сублимит.
Так как мы не знаем существует ли лимит, то всегда прикладываем эти параметры.
*/
struct LimitPlanChange {
1: required PlanID id
2: required LimitBatch batch
3: required LimitCreateParams create_params
}
/**
* Описывает время действия лимита:
* start_time - начало действия лимита
* end_time - конец, если не бесконечно
*/
struct LimitTimeRange {
1: required base.Timestamp start_time
2: optional base.Timestamp end_time
}
/**
* Описывает точку во времени жизни лимита:
* clock - clock состояния счета аккаунта, привязанного к сублимиту
* time_range - время действия сублимита, чтобы можно было его найти в лимите
*/
struct LimitClock {
1: required Clock clock
2: required LimitTimeRange time_range
}
exception LimitNotFound {
1: required LimitID limit_id
}
exception PlanNotFound {
1: required PlanID plan_id
}
/**
* Возникает в случае, если переданы некорректные параметры в одном или нескольких изменениях лимита
*/
exception InvalidLimitParams {
1: required map<LimitUnit, string> wrong_limits
}
exception ClockInFuture {}
service Accounter {
LimitClock Hold(1: LimitPlanChange plan_change) throws (1: InvalidLimitParams e1, 2: base.InvalidRequest e2)
LimitClock CommitPlan(1: LimitPlan plan) throws (1: InvalidLimitParams e1, 2: base.InvalidRequest e2)
LimitClock RollbackPlan(1: LimitPlan plan) throws (1: InvalidLimitParams e1, 2: base.InvalidRequest e2)
LimitPlan GetPlan(1: PlanID id) throws (1: PlanNotFound e1)
Limit GetLimitByID(1: LimitID id) throws (1:LimitNotFound e1)
Balance GetBalanceByID(1: LimitID id, 2: LimitClock clock) throws (1:LimitNotFound e1, 2: ClockInFuture e2)
} }

View File

@ -0,0 +1,87 @@
/**
* Машина хранящая конфигурацию лимита
*/
namespace java com.rbkmoney.limiter.config
namespace erlang limiter_config
include "base.thrift"
include "time_range.thrift"
/// Domain
typedef base.ID LimitConfigID
typedef base.Timestamp Timestamp
typedef base.Amount ShardSize
typedef base.CurrencySymbolicCode CurrencySymbolicCode
struct LimitConfig {
1: required LimitConfigID id
2: required string processor_type
3: required Timestamp created_at
4: required LimitBodyType body_type
5: required Timestamp started_at
6: required ShardSize shard_size
7: required time_range.TimeRangeType time_range_type
11: required LimitContextType context_type
8: optional LimitType type
9: optional LimitScope scope
10: optional string description
}
union LimitBodyType {
1: LimitBodyTypeAmount amount
2: LimitBodyTypeCash cash
}
struct LimitBodyTypeAmount {}
struct LimitBodyTypeCash {
1: required CurrencySymbolicCode currency
}
union LimitType {
1: LimitTypeTurnover turnover
}
struct LimitTypeTurnover {}
union LimitScope {
1: LimitScopeGlobal scope_global
2: LimitScopeType scope
}
struct LimitScopeGlobal {}
union LimitScopeType {
1: LimitScopeTypeParty party
2: LimitScopeTypeShop shop
3: LimitScopeTypeWallet wallet
4: LimitScopeTypeIdentity identity
}
struct LimitScopeTypeParty {}
struct LimitScopeTypeShop {}
struct LimitScopeTypeWallet {}
struct LimitScopeTypeIdentity {}
union LimitContextType {
1: LimitContextTypePaymentProcessing payment_processing
}
struct LimitContextTypePaymentProcessing {}
/// LimitConfig events
struct TimestampedChange {
1: required base.Timestamp occured_at
2: required Change change
}
union Change {
1: CreatedChange created
}
struct CreatedChange {
1: required LimitConfig limit_config
}

View File

@ -0,0 +1,103 @@
include "base.thrift"
namespace java com.rbkmoney.limiter.context
namespace erlang limiter_context
typedef base.ID ID
struct LimitContext {
1: optional ContextPaymentProcessing payment_processing
}
/**
* Контекст, получаемый из сервисов, реализующих один из интерфейсов протокола
* https://github.com/rbkmoney/damsel/tree/master/proto/payment_processing.thrift
* (например invoicing в hellgate)
*/
struct ContextPaymentProcessing {
1: optional PaymentProcessingOperation op
2: optional Invoice invoice
}
union PaymentProcessingOperation {
1: PaymentProcessingOperationInvoice invoice
2: PaymentProcessingOperationInvoiceAdjustment invoice_adjustment
3: PaymentProcessingOperationInvoicePayment invoice_payment
4: PaymentProcessingOperationInvoicePaymentAdjustment invoice_payment_adjustment
5: PaymentProcessingOperationInvoicePaymentRefund invoice_payment_refund
6: PaymentProcessingOperationInvoicePaymentChargeback invoice_payment_chargeback
}
struct PaymentProcessingOperationInvoice {}
struct PaymentProcessingOperationInvoiceAdjustment {}
struct PaymentProcessingOperationInvoicePayment {}
struct PaymentProcessingOperationInvoicePaymentAdjustment {}
struct PaymentProcessingOperationInvoicePaymentRefund {}
struct PaymentProcessingOperationInvoicePaymentChargeback {}
struct Invoice {
1: optional ID id
2: optional ID owner_id
3: optional ID shop_id
4: optional base.Cash cost
5: optional base.Timestamp created_at
6: optional InvoicePayment effective_payment
7: optional InvoiceAdjustment effective_adjustment
}
struct InvoiceAdjustment {
1: optional ID id
}
struct InvoicePayment {
1: optional ID id
2: optional ID owner_id
3: optional ID shop_id
4: optional base.Cash cost
11: optional base.Cash capture_cost
5: optional base.Timestamp created_at
6: optional InvoicePaymentFlow flow
7: optional Payer payer
8: optional InvoicePaymentAdjustment effective_adjustment
9: optional InvoicePaymentRefund effective_refund
10: optional InvoicePaymentChargeback effective_chargeback
}
/**
* Процесс выполнения платежа.
*/
union InvoicePaymentFlow {
1: InvoicePaymentFlowInstant instant
2: InvoicePaymentFlowHold hold
}
struct InvoicePaymentFlowInstant {}
struct InvoicePaymentFlowHold {}
union Payer {
1: PaymentResourcePayer payment_resource
2: CustomerPayer customer
3: RecurrentPayer recurrent
}
struct PaymentResourcePayer {}
struct CustomerPayer {}
struct RecurrentPayer {}
struct InvoicePaymentAdjustment {
1: optional ID id
2: optional base.Timestamp created_at
}
struct InvoicePaymentRefund {
1: optional ID id
2: optional base.Cash cost
3: optional base.Timestamp created_at
}
struct InvoicePaymentChargeback {
1: optional ID id
2: optional base.Timestamp created_at
3: optional base.Cash levy
4: optional base.Cash body
}

View File

@ -0,0 +1,49 @@
/**
* Машина хранящая временные интервалы
*/
namespace java com.rbkmoney.limiter.range
namespace erlang limiter_range
include "base.thrift"
include "time_range.thrift"
/// Domain
typedef base.ID LimitRangeID
typedef base.Timestamp Timestamp
struct LimitRange {
1: required LimitRangeID id
2: required time_range.TimeRangeType type
3: required Timestamp created_at
4: optional base.CurrencySymbolicCode currency
}
struct LimitRangeState {
1: required LimitRangeID id
2: required time_range.TimeRangeType type
3: required Timestamp created_at
4: optional list<time_range.TimeRange> ranges
5: optional base.CurrencySymbolicCode currency
}
/// LimitRange events
struct TimestampedChange {
1: required base.Timestamp occured_at
2: required Change change
}
union Change {
1: CreatedChange created
2: TimeRangeCreatedChange time_range_created
}
struct CreatedChange {
1: required LimitRange limit_range
}
struct TimeRangeCreatedChange {
1: required time_range.TimeRange time_range
}

43
proto/time_range.thrift Normal file
View File

@ -0,0 +1,43 @@
/**
* Временные интервалы
*/
namespace java com.rbkmoney.limiter.range.time
namespace erlang time_range
include "base.thrift"
/// Domain
typedef base.ID LimitRangeID
typedef base.AccountID AccountID
typedef base.Timestamp Timestamp
typedef base.Amount IntervalAmount
union TimeRangeType {
1: TimeRangeTypeCalendar calendar
2: TimeRangeTypeInterval interval
}
union TimeRangeTypeCalendar {
1: TimeRangeTypeCalendarYear year
2: TimeRangeTypeCalendarMonth month
3: TimeRangeTypeCalendarWeek week
4: TimeRangeTypeCalendarDay day
}
struct TimeRangeTypeCalendarYear {}
struct TimeRangeTypeCalendarMonth {}
struct TimeRangeTypeCalendarWeek {}
struct TimeRangeTypeCalendarDay {}
struct TimeRangeTypeInterval {
1: required IntervalAmount amount // in sec
}
struct TimeRange {
1: required Timestamp upper
2: required Timestamp lower
3: optional AccountID account_id_from
4: optional AccountID account_id_to
}

View File

@ -25,16 +25,7 @@
warn_missing_spec_all warn_missing_spec_all
]}. ]}.
{deps, [ {deps, []}.
{msgpack_proto,
{git, "git@github.com:rbkmoney/msgpack-proto.git",
{branch, "master"}}
},
{shumpune_proto,
{git, "git@github.com:rbkmoney/shumpune-proto.git",
{branch, "master"}}
}
]}.
%% XRef checks %% XRef checks
{xref_checks, [ {xref_checks, [
@ -44,9 +35,6 @@
deprecated_functions deprecated_functions
]}. ]}.
%% Tests
{cover_enabled, true}.
%% Dialyzer static analyzing %% Dialyzer static analyzing
{dialyzer, [ {dialyzer, [
{warnings, [ {warnings, [
@ -73,8 +61,5 @@
{thrift_compiler_opts, [ {thrift_compiler_opts, [
{in_dir, "proto"}, {in_dir, "proto"},
{in_files, [ {gen, "erlang:scoped_typenames,app_prefix=lim"}
"limiter.thrift"
]},
{gen, "erlang:scoped_typenames"}
]}. ]}.

View File

@ -1,8 +1 @@
[{<<"msgpack_proto">>, [].
{git,"git@github.com:rbkmoney/msgpack-proto.git",
{ref,"b558b0d9a91f2130e241bd186db171aee3e81e36"}},
0},
{<<"shumpune_proto">>,
{git,"git@github.com:rbkmoney/shumpune-proto.git",
{ref,"4c87f03591cae3dad41504eb463d962af536b1ab"}},
0}].