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') {
env.JENKINS_LIB = "build_utils/jenkins_lib"
pipeDefault = load("${env.JENKINS_LIB}/pipeDefault.groovy")
pipeJavaProto = load("${env.JENKINS_LIB}/pipeJavaProto.groovy")
gitUtils = load("${env.JENKINS_LIB}/gitUtils.groovy")
}
pipeDefault() {
runStage('compile') {
withGithubPrivkey {
sh "make submodules"
sh "make wc_compile"
}
sh "make wc_compile"
}
// Java
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'
}
}
}
env.skipSonar = 'true'
pipeJavaProto()
}
}

View File

@ -7,13 +7,12 @@ UTILS_PATH := build_utils
TEMPLATES_PATH := .
# Name of the service
SERVICE_NAME := limiter_proto
SERVICE_NAME := limiter-proto
# Build image tag to be used
BUILD_IMAGE_TAG := eee42f2ca018c313190bc350fe47d4dea70b6d27
BUILD_IMAGE_TAG := b04c5291d101132e53e578d96e1628d2e6dab0c0
CALL_ANYWHERE := \
all submodules rebar-update compile clean distclean \
java.compile java.deploy
all submodules compile clean distclean
CALL_W_CONTAINER := $(CALL_ANYWHERE)
@ -30,10 +29,7 @@ $(SUBTARGETS): %/.git: %
submodules: $(SUBTARGETS)
rebar-update:
$(REBAR) update
compile: submodules
compile:
$(REBAR) compile
clean:
@ -41,43 +37,6 @@ clean:
distclean:
$(REBAR) clean -a
rm -rfv _build _builds _cache _steps _temp
rm -rfv _build
# Java
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)
include $(UTILS_PATH)/make_lib/java_proto.mk

@ -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 erlang limiter
include "proto/shumpune.thrift"
include "proto/base.thrift"
typedef string LimitID
typedef string PlanID
typedef i64 BatchID
typedef i64 AccountID
typedef string LimitRef
typedef i64 DomainRevision
typedef shumpune.Clock Clock
typedef shumpune.Balance Balance
typedef base.InvalidRequest InvalidRequest
typedef base.ID LimitChangeID
typedef base.ID LimitID
typedef base.ID PartyID
typedef base.ID ShopID
typedef base.ID WalletID
typedef base.ID IdentityID
typedef limiter_context.LimitContext LimitContext
/**
* Описывает типы лимитов:
* cash - валютный лимит - ассоциирован с изменением сумм в какой-либо валюте
* count - счетный лимит - ассоциирован с количеством каких-либо операций в системе
*/
enum LimitType {
cash
count
* https://en.wikipedia.org/wiki/Vector_clock
**/
struct VectorClock {
1: required base.Opaque state
}
/**
* Структура данных, описывающая свойства сублимита:
* account_id -идентификатор аккаунта ассоциированного с временным действием сублимита
* time_range - время действия сублимита
*/
struct Sublimit {
1: required AccountID account_id
2: required LimitTimeRange time_range
* Структура, позволяющая установить причинно-следственную связь операций внутри сервиса
**/
union Clock {
1: VectorClock vector
}
/**
* Структура данных, описывающая свойства лимита:
* id -идентификатор машины лимита
* ref - идентификатор лимита в domain конфигурации
* domain_revision - ревизия конфигурации
* type - тип лимита
* sublimits - сублимиты лимита
* description - описание (неизменяемо после создания лимита)
*/
struct Limit {
1: required LimitID id
2: required LimitRef ref
3: required DomainRevision domain_revision
4: required LimitType type
5: required list<Sublimit> sublimits
6: optional string description
2: required base.Amount amount
3: optional base.Timestamp creation_time
4: optional string description
}
/**
* Описывает одно изменение лимита в системе, может быть следующих типов:
* cash - изменение валютного лимита
* count - изменение счетного лимита
*/
union LimitUnit {
1: LimitUnitCash cash
2: LimitUnitCount count
struct LimitChange {
1: required LimitID id
2: required LimitChangeID change_id
}
struct LimitUnitCash {
exception LimitNotFound {}
exception LimitChangeNotFound {}
exception ForbiddenOperationAmount {
1: required base.Amount amount
2: required base.CurrencySymbolicCode currency_sym_code
2: required base.AmountRange allowed_range
}
struct LimitUnitCount {
1: required base.Amount amount
}
/**
* Описывает батч - набор изменений лимита, служит единицей атомарности операций в системе:
* id - идентификатор набора, уникален в пределах плана
* units - набор изменений лимита
*/
struct LimitBatch {
1: required BatchID id
2: required list<LimitUnit> units
}
/**
* План состоит из набора батчей, который можно пополнить, подтвердить или отменить:
* 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)
service Limiter {
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 (
1: LimitNotFound e1,
3: base.InvalidRequest e2
)
Clock Commit(1: LimitChange change, 2: Clock clock, 3: LimitContext context) throws (
1: LimitNotFound e1,
2: LimitChangeNotFound e2,
3: base.InvalidRequest e3,
4: ForbiddenOperationAmount e4
)
}

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
]}.
{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"}}
}
]}.
{deps, []}.
%% XRef checks
{xref_checks, [
@ -44,9 +35,6 @@
deprecated_functions
]}.
%% Tests
{cover_enabled, true}.
%% Dialyzer static analyzing
{dialyzer, [
{warnings, [
@ -73,8 +61,5 @@
{thrift_compiler_opts, [
{in_dir, "proto"},
{in_files, [
"limiter.thrift"
]},
{gen, "erlang:scoped_typenames"}
{gen, "erlang:scoped_typenames,app_prefix=lim"}
]}.

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}].
[].