diff --git a/.DS_Store b/.DS_Store
new file mode 100644
index 000000000..81229e8d2
Binary files /dev/null and b/.DS_Store differ
diff --git a/.gitignore b/.gitignore
index 259113f73..4beaadeee 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,8 @@ target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
+prometheus/data/
+grafana/data/
### STS ###
.apt_generated
@@ -18,7 +20,7 @@ target/
*.iws
*.iml
*.ipr
-./http-client.env.json
+http-client.env.json
### NetBeans ###
/nbproject/private/
diff --git a/grafana/provisioning/dashboards/ServicesStatistic.json b/grafana/provisioning/dashboards/ServicesStatistic.json
index 684b97269..0c32b8927 100644
--- a/grafana/provisioning/dashboards/ServicesStatistic.json
+++ b/grafana/provisioning/dashboards/ServicesStatistic.json
@@ -24,614 +24,760 @@
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 1,
- "id": 4,
"links": [],
"liveNow": true,
"panels": [
{
- "collapsed": true,
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 0,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "auto",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ }
+ },
+ "overrides": []
+ },
"gridPos": {
- "h": 1,
- "w": 24,
+ "h": 8,
+ "w": 12,
"x": 0,
"y": 0
},
- "id": 27,
- "panels": [
+ "id": 103,
+ "options": {
+ "legend": {
+ "calcs": [],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "maxHeight": 600,
+ "mode": "single",
+ "sort": "none"
+ }
+ },
+ "targets": [
{
"datasource": {
"type": "prometheus",
"uid": "PBFA97CFB590B2093"
},
- "fieldConfig": {
- "defaults": {
- "color": {
- "mode": "palette-classic"
- },
- "custom": {
- "axisBorderShow": false,
- "axisCenteredZero": false,
- "axisColorMode": "text",
- "axisLabel": "",
- "axisPlacement": "auto",
- "barAlignment": 0,
- "barWidthFactor": 0.6,
- "drawStyle": "bars",
- "fillOpacity": 23,
- "gradientMode": "hue",
- "hideFrom": {
- "legend": false,
- "tooltip": false,
- "viz": false
- },
- "insertNulls": false,
- "lineInterpolation": "linear",
- "lineWidth": 1,
- "pointSize": 5,
- "scaleDistribution": {
- "type": "linear"
- },
- "showPoints": "never",
- "spanNulls": false,
- "stacking": {
- "group": "A",
- "mode": "normal"
- },
- "thresholdsStyle": {
- "mode": "off"
- }
- },
- "mappings": [],
- "noValue": "0",
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- },
- {
- "color": "red",
- "value": 80
- }
- ]
- }
- },
- "overrides": []
- },
- "gridPos": {
- "h": 8,
- "w": 12,
- "x": 0,
- "y": 1
- },
- "id": 29,
- "options": {
- "legend": {
- "calcs": [],
- "displayMode": "table",
- "placement": "right",
- "showLegend": true
- },
- "tooltip": {
- "mode": "single",
- "sort": "none"
- }
- },
- "pluginVersion": "11.4.0",
- "targets": [
- {
- "datasource": {
- "type": "prometheus",
- "uid": "PBFA97CFB590B2093"
- },
- "editorMode": "code",
- "expr": "sum(rate(payment_finished_total{service=~\"$service\"}[30s])) by (service, outcome, failReason)",
- "hide": false,
- "instant": false,
- "legendFormat": "{{outcome}} - {{failReason}}",
- "range": true,
- "refId": "B"
- }
- ],
- "title": "Payments outcome rate per second",
- "type": "timeseries"
+ "editorMode": "code",
+ "expr": "increase(payment_requests_incoming_total[5m])",
+ "instant": false,
+ "legendFormat": "incoming",
+ "range": true,
+ "refId": "A"
},
{
"datasource": {
"type": "prometheus",
"uid": "PBFA97CFB590B2093"
},
- "fieldConfig": {
- "defaults": {
- "color": {
- "mode": "palette-classic"
- },
- "custom": {
- "axisBorderShow": false,
- "axisCenteredZero": false,
- "axisColorMode": "text",
- "axisLabel": "",
- "axisPlacement": "auto",
- "barAlignment": 0,
- "barWidthFactor": 0.6,
- "drawStyle": "line",
- "fillOpacity": 0,
- "gradientMode": "none",
- "hideFrom": {
- "legend": false,
- "tooltip": false,
- "viz": false
- },
- "insertNulls": false,
- "lineInterpolation": "linear",
- "lineWidth": 1,
- "pointSize": 5,
- "scaleDistribution": {
- "type": "linear"
- },
- "showPoints": "auto",
- "spanNulls": false,
- "stacking": {
- "group": "A",
- "mode": "none"
- },
- "thresholdsStyle": {
- "mode": "off"
- }
- },
- "mappings": [],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- },
- {
- "color": "red",
- "value": 80
- }
- ]
- }
- },
- "overrides": []
- },
- "gridPos": {
- "h": 8,
- "w": 12,
- "x": 12,
- "y": 1
- },
- "id": 26,
- "options": {
- "legend": {
- "calcs": [],
- "displayMode": "table",
- "placement": "right",
- "showLegend": true
- },
- "tooltip": {
- "mode": "single",
- "sort": "none"
- }
- },
- "pluginVersion": "11.4.0",
- "targets": [
- {
- "datasource": {
- "type": "prometheus",
- "uid": "PBFA97CFB590B2093"
- },
- "editorMode": "code",
- "exemplar": true,
- "expr": "sum by (type) (rate(events_total{}[30s]))",
- "interval": "",
- "legendFormat": "{{type}}",
- "range": true,
- "refId": "A"
- }
- ],
- "title": "Event during testing per second",
- "type": "timeseries"
+ "editorMode": "code",
+ "expr": "increase(payment_requests_outgoing_total[5m])",
+ "hide": false,
+ "instant": false,
+ "legendFormat": "outgoing",
+ "range": true,
+ "refId": "B"
},
{
"datasource": {
"type": "prometheus",
"uid": "PBFA97CFB590B2093"
},
- "fieldConfig": {
- "defaults": {
- "color": {
- "mode": "palette-classic"
- },
- "custom": {
- "axisBorderShow": false,
- "axisCenteredZero": false,
- "axisColorMode": "text",
- "axisLabel": "",
- "axisPlacement": "auto",
- "barAlignment": 0,
- "barWidthFactor": 0.6,
- "drawStyle": "bars",
- "fillOpacity": 23,
- "gradientMode": "hue",
- "hideFrom": {
- "legend": false,
- "tooltip": false,
- "viz": false
- },
- "insertNulls": false,
- "lineInterpolation": "linear",
- "lineWidth": 1,
- "pointSize": 5,
- "scaleDistribution": {
- "type": "linear"
- },
- "showPoints": "never",
- "spanNulls": false,
- "stacking": {
- "group": "A",
- "mode": "percent"
- },
- "thresholdsStyle": {
- "mode": "off"
- }
- },
- "mappings": [],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- },
- {
- "color": "red",
- "value": 80
- }
- ]
- },
- "unit": "percentunit"
- },
- "overrides": []
- },
- "gridPos": {
- "h": 8,
- "w": 12,
- "x": 0,
- "y": 265
- },
- "id": 28,
- "options": {
- "legend": {
- "calcs": [],
- "displayMode": "table",
- "placement": "right",
- "showLegend": true
- },
- "tooltip": {
- "mode": "single",
- "sort": "none"
- }
- },
- "pluginVersion": "11.4.0",
- "targets": [
- {
- "datasource": {
- "type": "prometheus",
- "uid": "PBFA97CFB590B2093"
- },
- "editorMode": "code",
- "expr": "sum(increase(payments_amount_total{service=~\"$service\"}[1m])) by (service) / (sum(increase(payments_amount_total{service=~\"$service\"}[1m])) by (service) + sum(increase(external_amount_total{service=~\"$service\"}[1m])) by (service))",
- "hide": false,
- "instant": false,
- "legendFormat": "income - {{service}}",
- "range": true,
- "refId": "B"
- },
- {
- "datasource": {
- "type": "prometheus",
- "uid": "PBFA97CFB590B2093"
- },
- "editorMode": "code",
- "expr": "sum(increase(external_amount_total{service=~\"$service\"}[1m])) by (service) / (sum(increase(payments_amount_total{service=~\"$service\"}[1m])) by (service) + sum(increase(external_amount_total{service=~\"$service\"}[1m])) by (service))",
- "hide": false,
- "instant": false,
- "legendFormat": "expenses - {{service}} ",
- "range": true,
- "refId": "A"
- }
- ],
- "title": "Income / Expenses percentage",
- "type": "timeseries"
+ "editorMode": "code",
+ "expr": "increase(payment_requests_completed_total[5m])",
+ "hide": false,
+ "instant": false,
+ "legendFormat": "completed",
+ "range": true,
+ "refId": "C"
},
{
"datasource": {
"type": "prometheus",
"uid": "PBFA97CFB590B2093"
},
- "fieldConfig": {
- "defaults": {
- "color": {
- "mode": "continuous-RdYlGr"
- },
- "mappings": [],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- },
- {
- "color": "red",
- "value": 80
- }
- ]
- },
- "unit": "percentunit"
- },
- "overrides": []
- },
- "gridPos": {
- "h": 8,
- "w": 12,
- "x": 12,
- "y": 265
- },
- "id": 36,
- "options": {
- "colorMode": "value",
- "graphMode": "area",
- "justifyMode": "auto",
- "orientation": "auto",
- "percentChangeColorMode": "standard",
- "reduceOptions": {
- "calcs": [
- "lastNotNull"
- ],
- "fields": "",
- "values": false
- },
- "showPercentChange": false,
- "textMode": "auto",
- "wideLayout": true
+ "editorMode": "code",
+ "expr": "increase(payment_requests_failed_total[5m])",
+ "hide": false,
+ "instant": false,
+ "legendFormat": "failed",
+ "range": true,
+ "refId": "D"
+ }
+ ],
+ "title": "Servise request increase",
+ "type": "timeseries"
+ },
+ {
+ "collapsed": false,
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 8
+ },
+ "id": 102,
+ "panels": [],
+ "title": "Custom",
+ "type": "row"
+ },
+ {
+ "collapsed": false,
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 9
+ },
+ "id": 27,
+ "panels": [],
+ "title": "General",
+ "type": "row"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "bars",
+ "fillOpacity": 23,
+ "gradientMode": "hue",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "never",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "normal"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
},
- "pluginVersion": "11.4.0",
- "targets": [
- {
- "datasource": {
- "type": "prometheus",
- "uid": "PBFA97CFB590B2093"
- },
- "editorMode": "code",
- "expr": "sum(increase(payments_amount_total{service=~\"$service\"}[$__range])) by (service) / (sum(increase(payments_amount_total{service=~\"$service\"}[$__range])) by (service) + sum(increase(external_amount_total{service=~\"$service\"}[$__range])) by (service))",
- "hide": false,
- "instant": false,
- "legendFormat": "income - {{service}}",
- "range": true,
- "refId": "B"
- },
- {
- "datasource": {
- "type": "prometheus",
- "uid": "PBFA97CFB590B2093"
+ "mappings": [],
+ "noValue": "0",
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
},
- "editorMode": "code",
- "expr": "sum(increase(external_amount_total{service=~\"$service\"}[$__range])) by (service) / (sum(increase(payments_amount_total{service=~\"$service\"}[$__range])) by (service) + sum(increase(external_amount_total{service=~\"$service\"}[$__range])) by (service))",
- "hide": false,
- "instant": false,
- "legendFormat": "expenses - {{service}} ",
- "range": true,
- "refId": "A"
- }
- ],
- "title": "Income / Expenses percentage",
- "type": "stat"
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ }
},
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 8,
+ "w": 12,
+ "x": 0,
+ "y": 10
+ },
+ "id": 29,
+ "options": {
+ "legend": {
+ "calcs": [],
+ "displayMode": "table",
+ "placement": "right",
+ "showLegend": true
+ },
+ "tooltip": {
+ "maxHeight": 600,
+ "mode": "single",
+ "sort": "none"
+ }
+ },
+ "pluginVersion": "11.4.0",
+ "targets": [
{
"datasource": {
"type": "prometheus",
"uid": "PBFA97CFB590B2093"
},
- "fieldConfig": {
- "defaults": {
- "color": {
- "mode": "palette-classic"
- },
- "custom": {
- "axisBorderShow": false,
- "axisCenteredZero": false,
- "axisColorMode": "text",
- "axisLabel": "",
- "axisPlacement": "auto",
- "barAlignment": 0,
- "barWidthFactor": 0.6,
- "drawStyle": "bars",
- "fillOpacity": 23,
- "gradientMode": "hue",
- "hideFrom": {
- "legend": false,
- "tooltip": false,
- "viz": false
- },
- "insertNulls": false,
- "lineInterpolation": "linear",
- "lineWidth": 1,
- "pointSize": 5,
- "scaleDistribution": {
- "type": "linear"
- },
- "showPoints": "never",
- "spanNulls": false,
- "stacking": {
- "group": "A",
- "mode": "none"
- },
- "thresholdsStyle": {
- "mode": "off"
- }
- },
- "mappings": [],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- },
- {
- "color": "red",
- "value": 80
- }
- ]
- },
- "unit": "short"
- },
- "overrides": []
+ "editorMode": "code",
+ "expr": "sum(rate(payment_finished_total{service=~\"$service\"}[30s])) by (service, outcome, failReason)",
+ "hide": false,
+ "instant": false,
+ "legendFormat": "{{outcome}} - {{failReason}}",
+ "range": true,
+ "refId": "B"
+ }
+ ],
+ "title": "Payments outcome rate per second",
+ "type": "timeseries"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 0,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "auto",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
},
- "gridPos": {
- "h": 8,
- "w": 12,
- "x": 0,
- "y": 273
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ }
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 8,
+ "w": 12,
+ "x": 12,
+ "y": 10
+ },
+ "id": 26,
+ "options": {
+ "legend": {
+ "calcs": [],
+ "displayMode": "table",
+ "placement": "right",
+ "showLegend": true
+ },
+ "tooltip": {
+ "maxHeight": 600,
+ "mode": "single",
+ "sort": "none"
+ }
+ },
+ "pluginVersion": "11.4.0",
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
},
- "id": 37,
- "options": {
- "legend": {
- "calcs": [
- "lastNotNull"
- ],
- "displayMode": "table",
- "placement": "right",
- "showLegend": true
- },
- "tooltip": {
- "mode": "single",
- "sort": "none"
+ "editorMode": "code",
+ "exemplar": true,
+ "expr": "sum by (type) (rate(events_total{}[30s]))",
+ "interval": "",
+ "legendFormat": "{{type}}",
+ "range": true,
+ "refId": "A"
+ }
+ ],
+ "title": "Event during testing per second",
+ "type": "timeseries"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "bars",
+ "fillOpacity": 23,
+ "gradientMode": "hue",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "never",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "percent"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
}
},
- "pluginVersion": "11.4.0",
- "targets": [
- {
- "datasource": {
- "type": "prometheus",
- "uid": "PBFA97CFB590B2093"
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
},
- "editorMode": "code",
- "expr": "sum(increase(payments_amount_total{service=~\"$service\"}[1m])) by (service)",
- "hide": false,
- "instant": false,
- "legendFormat": "income - {{service}}",
- "range": true,
- "refId": "B"
- },
- {
- "datasource": {
- "type": "prometheus",
- "uid": "PBFA97CFB590B2093"
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "percentunit"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 8,
+ "w": 12,
+ "x": 0,
+ "y": 18
+ },
+ "id": 28,
+ "options": {
+ "legend": {
+ "calcs": [],
+ "displayMode": "table",
+ "placement": "right",
+ "showLegend": true
+ },
+ "tooltip": {
+ "maxHeight": 600,
+ "mode": "single",
+ "sort": "none"
+ }
+ },
+ "pluginVersion": "11.4.0",
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "editorMode": "code",
+ "expr": "sum(increase(payments_amount_total{service=~\"$service\"}[1m])) by (service) / (sum(increase(payments_amount_total{service=~\"$service\"}[1m])) by (service) + sum(increase(external_amount_total{service=~\"$service\"}[1m])) by (service))",
+ "hide": false,
+ "instant": false,
+ "legendFormat": "income - {{service}}",
+ "range": true,
+ "refId": "B"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "editorMode": "code",
+ "expr": "sum(increase(external_amount_total{service=~\"$service\"}[1m])) by (service) / (sum(increase(payments_amount_total{service=~\"$service\"}[1m])) by (service) + sum(increase(external_amount_total{service=~\"$service\"}[1m])) by (service))",
+ "hide": false,
+ "instant": false,
+ "legendFormat": "expenses - {{service}} ",
+ "range": true,
+ "refId": "A"
+ }
+ ],
+ "title": "Income / Expenses percentage",
+ "type": "timeseries"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "continuous-RdYlGr"
+ },
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
},
- "editorMode": "code",
- "expr": "sum(increase(external_amount_total{service=~\"$service\"}[1m])) by (service, accountName) ",
- "hide": false,
- "instant": false,
- "legendFormat": "expenses - {{service}} - {{accountName}}",
- "range": true,
- "refId": "A"
- }
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "percentunit"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 8,
+ "w": 12,
+ "x": 12,
+ "y": 18
+ },
+ "id": 36,
+ "options": {
+ "colorMode": "value",
+ "graphMode": "area",
+ "justifyMode": "auto",
+ "orientation": "auto",
+ "percentChangeColorMode": "standard",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
],
- "title": "Income / Expenses amount",
- "type": "timeseries"
+ "fields": "",
+ "values": false
},
+ "showPercentChange": false,
+ "textMode": "auto",
+ "wideLayout": true
+ },
+ "pluginVersion": "11.0.0",
+ "targets": [
{
"datasource": {
"type": "prometheus",
"uid": "PBFA97CFB590B2093"
},
- "fieldConfig": {
- "defaults": {
- "color": {
- "mode": "continuous-RdYlGr"
- },
- "mappings": [],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- },
- {
- "color": "red",
- "value": 80
- }
- ]
+ "editorMode": "code",
+ "expr": "sum(increase(payments_amount_total{service=~\"$service\"}[$__range])) by (service) / (sum(increase(payments_amount_total{service=~\"$service\"}[$__range])) by (service) + sum(increase(external_amount_total{service=~\"$service\"}[$__range])) by (service))",
+ "hide": false,
+ "instant": false,
+ "legendFormat": "income - {{service}}",
+ "range": true,
+ "refId": "B"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "editorMode": "code",
+ "expr": "sum(increase(external_amount_total{service=~\"$service\"}[$__range])) by (service) / (sum(increase(payments_amount_total{service=~\"$service\"}[$__range])) by (service) + sum(increase(external_amount_total{service=~\"$service\"}[$__range])) by (service))",
+ "hide": false,
+ "instant": false,
+ "legendFormat": "expenses - {{service}} ",
+ "range": true,
+ "refId": "A"
+ }
+ ],
+ "title": "Income / Expenses percentage",
+ "type": "stat"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "bars",
+ "fillOpacity": 23,
+ "gradientMode": "hue",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "never",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
},
- "unit": "short"
- },
- "overrides": []
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
},
- "gridPos": {
- "h": 8,
- "w": 12,
- "x": 12,
- "y": 273
+ "unit": "short"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 8,
+ "w": 12,
+ "x": 0,
+ "y": 26
+ },
+ "id": 37,
+ "options": {
+ "legend": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "displayMode": "table",
+ "placement": "right",
+ "showLegend": true
+ },
+ "tooltip": {
+ "maxHeight": 600,
+ "mode": "single",
+ "sort": "none"
+ }
+ },
+ "pluginVersion": "11.4.0",
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
},
- "id": 31,
- "options": {
- "colorMode": "value",
- "graphMode": "area",
- "justifyMode": "auto",
- "orientation": "auto",
- "percentChangeColorMode": "standard",
- "reduceOptions": {
- "calcs": [
- "lastNotNull"
- ],
- "fields": "",
- "values": false
- },
- "showPercentChange": false,
- "textMode": "auto",
- "wideLayout": true
+ "editorMode": "code",
+ "expr": "sum(increase(payments_amount_total{service=~\"$service\"}[1m])) by (service)",
+ "hide": false,
+ "instant": false,
+ "legendFormat": "income - {{service}}",
+ "range": true,
+ "refId": "B"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
},
- "pluginVersion": "11.4.0",
- "targets": [
- {
- "datasource": {
- "type": "prometheus",
- "uid": "PBFA97CFB590B2093"
- },
- "editorMode": "code",
- "expr": "sum(increase(payments_amount_total{service=~\"$service\"}[$__range])) by (service)",
- "hide": false,
- "instant": false,
- "legendFormat": "income - {{service}}",
- "range": true,
- "refId": "B"
- },
- {
- "datasource": {
- "type": "prometheus",
- "uid": "PBFA97CFB590B2093"
+ "editorMode": "code",
+ "expr": "sum(increase(external_amount_total{service=~\"$service\"}[1m])) by (service, accountName) ",
+ "hide": false,
+ "instant": false,
+ "legendFormat": "expenses - {{service}} - {{accountName}}",
+ "range": true,
+ "refId": "A"
+ }
+ ],
+ "title": "Income / Expenses amount",
+ "type": "timeseries"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "continuous-RdYlGr"
+ },
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
},
- "editorMode": "code",
- "expr": "sum(increase(external_amount_total{service=~\"$service\"}[$__range])) by (service, accountName) ",
- "hide": false,
- "instant": false,
- "legendFormat": "expenses - {{service}} - {{accountName}}",
- "range": true,
- "refId": "A"
- }
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "short"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 8,
+ "w": 12,
+ "x": 12,
+ "y": 26
+ },
+ "id": 31,
+ "options": {
+ "colorMode": "value",
+ "graphMode": "area",
+ "justifyMode": "auto",
+ "orientation": "auto",
+ "percentChangeColorMode": "standard",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
],
- "title": "Income / Expenses amount",
- "type": "stat"
+ "fields": "",
+ "values": false
+ },
+ "showPercentChange": false,
+ "textMode": "auto",
+ "wideLayout": true
+ },
+ "pluginVersion": "11.0.0",
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "editorMode": "code",
+ "expr": "sum(increase(payments_amount_total{service=~\"$service\"}[$__range])) by (service)",
+ "hide": false,
+ "instant": false,
+ "legendFormat": "income - {{service}}",
+ "range": true,
+ "refId": "B"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "editorMode": "code",
+ "expr": "sum(increase(external_amount_total{service=~\"$service\"}[$__range])) by (service, accountName) ",
+ "hide": false,
+ "instant": false,
+ "legendFormat": "expenses - {{service}} - {{accountName}}",
+ "range": true,
+ "refId": "A"
}
],
- "title": "General",
- "type": "row"
+ "title": "Income / Expenses amount",
+ "type": "stat"
},
{
"collapsed": true,
@@ -639,7 +785,7 @@
"h": 1,
"w": 24,
"x": 0,
- "y": 1
+ "y": 34
},
"id": 10,
"panels": [
@@ -658,8 +804,7 @@
"mode": "absolute",
"steps": [
{
- "color": "green",
- "value": null
+ "color": "green"
}
]
}
@@ -701,7 +846,7 @@
"h": 8,
"w": 12,
"x": 0,
- "y": 2
+ "y": 18
},
"id": 2,
"options": {
@@ -792,8 +937,7 @@
"mode": "absolute",
"steps": [
{
- "color": "green",
- "value": null
+ "color": "green"
},
{
"color": "red",
@@ -840,7 +984,7 @@
"h": 8,
"w": 12,
"x": 12,
- "y": 2
+ "y": 18
},
"id": 13,
"options": {
@@ -924,8 +1068,7 @@
"mode": "absolute",
"steps": [
{
- "color": "green",
- "value": null
+ "color": "green"
},
{
"color": "red",
@@ -941,7 +1084,7 @@
"h": 8,
"w": 12,
"x": 0,
- "y": 226
+ "y": 242
},
"id": 25,
"options": {
@@ -985,7 +1128,7 @@
"h": 1,
"w": 24,
"x": 0,
- "y": 2
+ "y": 35
},
"id": 12,
"panels": [
@@ -1040,8 +1183,7 @@
"mode": "absolute",
"steps": [
{
- "color": "green",
- "value": null
+ "color": "green"
},
{
"color": "red",
@@ -1087,7 +1229,7 @@
"h": 8,
"w": 12,
"x": 0,
- "y": 3
+ "y": 19
},
"id": 7,
"options": {
@@ -1174,8 +1316,7 @@
"mode": "absolute",
"steps": [
{
- "color": "green",
- "value": null
+ "color": "green"
},
{
"color": "red",
@@ -1222,7 +1363,7 @@
"h": 8,
"w": 12,
"x": 12,
- "y": 3
+ "y": 19
},
"id": 8,
"options": {
@@ -1307,8 +1448,7 @@
"mode": "absolute",
"steps": [
{
- "color": "green",
- "value": null
+ "color": "green"
}
]
},
@@ -1320,7 +1460,7 @@
"h": 8,
"w": 12,
"x": 0,
- "y": 123
+ "y": 139
},
"id": 30,
"options": {
@@ -1378,7 +1518,7 @@
"h": 1,
"w": 24,
"x": 0,
- "y": 3
+ "y": 36
},
"id": 17,
"panels": [
@@ -1433,8 +1573,7 @@
"mode": "absolute",
"steps": [
{
- "color": "green",
- "value": null
+ "color": "green"
},
{
"color": "red",
@@ -1481,7 +1620,7 @@
"h": 8,
"w": 12,
"x": 0,
- "y": 4
+ "y": 20
},
"id": 3,
"options": {
@@ -1569,8 +1708,7 @@
"mode": "absolute",
"steps": [
{
- "color": "green",
- "value": null
+ "color": "green"
},
{
"color": "red",
@@ -1617,7 +1755,7 @@
"h": 8,
"w": 12,
"x": 12,
- "y": 4
+ "y": 20
},
"id": 14,
"options": {
@@ -1707,8 +1845,7 @@
"mode": "absolute",
"steps": [
{
- "color": "green",
- "value": null
+ "color": "green"
},
{
"color": "red",
@@ -1755,7 +1892,7 @@
"h": 8,
"w": 12,
"x": 0,
- "y": 100
+ "y": 116
},
"id": 32,
"options": {
@@ -1845,8 +1982,7 @@
"mode": "absolute",
"steps": [
{
- "color": "green",
- "value": null
+ "color": "green"
},
{
"color": "red",
@@ -1893,7 +2029,7 @@
"h": 8,
"w": 12,
"x": 12,
- "y": 100
+ "y": 116
},
"id": 34,
"options": {
@@ -1983,8 +2119,7 @@
"mode": "absolute",
"steps": [
{
- "color": "green",
- "value": null
+ "color": "green"
},
{
"color": "red",
@@ -2055,7 +2190,7 @@
"h": 8,
"w": 12,
"x": 12,
- "y": 108
+ "y": 124
},
"id": 43,
"options": {
@@ -2103,7 +2238,7 @@
"h": 1,
"w": 24,
"x": 0,
- "y": 4
+ "y": 37
},
"id": 21,
"panels": [
@@ -2155,8 +2290,7 @@
"mode": "absolute",
"steps": [
{
- "color": "green",
- "value": null
+ "color": "green"
},
{
"color": "red",
@@ -2171,7 +2305,7 @@
"h": 8,
"w": 12,
"x": 0,
- "y": 5
+ "y": 21
},
"id": 19,
"options": {
@@ -2253,8 +2387,7 @@
"mode": "absolute",
"steps": [
{
- "color": "green",
- "value": null
+ "color": "green"
},
{
"color": "red",
@@ -2269,7 +2402,7 @@
"h": 8,
"w": 12,
"x": 12,
- "y": 5
+ "y": 21
},
"id": 22,
"options": {
@@ -2351,8 +2484,7 @@
"mode": "absolute",
"steps": [
{
- "color": "green",
- "value": null
+ "color": "green"
},
{
"color": "red",
@@ -2367,7 +2499,7 @@
"h": 8,
"w": 12,
"x": 12,
- "y": 85
+ "y": 101
},
"id": 100,
"options": {
@@ -2411,7 +2543,7 @@
"h": 1,
"w": 24,
"x": 0,
- "y": 5
+ "y": 38
},
"id": 38,
"panels": [
@@ -2463,8 +2595,7 @@
"mode": "absolute",
"steps": [
{
- "color": "green",
- "value": null
+ "color": "green"
}
]
},
@@ -2476,7 +2607,7 @@
"h": 8,
"w": 12,
"x": 0,
- "y": 6
+ "y": 22
},
"id": 40,
"options": {
@@ -2557,8 +2688,7 @@
"mode": "absolute",
"steps": [
{
- "color": "green",
- "value": null
+ "color": "green"
}
]
},
@@ -2570,7 +2700,7 @@
"h": 8,
"w": 12,
"x": 12,
- "y": 6
+ "y": 22
},
"id": 39,
"options": {
@@ -2652,8 +2782,7 @@
"mode": "absolute",
"steps": [
{
- "color": "green",
- "value": null
+ "color": "green"
},
{
"color": "red",
@@ -2669,7 +2798,7 @@
"h": 8,
"w": 12,
"x": 0,
- "y": 38
+ "y": 54
},
"id": 95,
"options": {
@@ -2766,8 +2895,7 @@
"mode": "absolute",
"steps": [
{
- "color": "green",
- "value": null
+ "color": "green"
}
]
},
@@ -2779,7 +2907,7 @@
"h": 8,
"w": 12,
"x": 12,
- "y": 38
+ "y": 54
},
"id": 42,
"options": {
@@ -2860,8 +2988,7 @@
"mode": "absolute",
"steps": [
{
- "color": "green",
- "value": null
+ "color": "green"
}
]
},
@@ -2873,7 +3000,7 @@
"h": 8,
"w": 12,
"x": 0,
- "y": 46
+ "y": 62
},
"id": 41,
"options": {
@@ -2916,7 +3043,7 @@
"h": 1,
"w": 24,
"x": 0,
- "y": 6
+ "y": 39
},
"id": 97,
"panels": [
@@ -2937,7 +3064,6 @@
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
- "barWidthFactor": 0.6,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
@@ -2984,7 +3110,7 @@
"h": 8,
"w": 12,
"x": 0,
- "y": 7
+ "y": 47
},
"id": 98,
"maxDataPoints": 100,
@@ -2998,6 +3124,7 @@
"showLegend": true
},
"tooltip": {
+ "maxHeight": 600,
"mode": "single",
"sort": "none"
}
@@ -3039,7 +3166,6 @@
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
- "barWidthFactor": 0.6,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
@@ -3086,7 +3212,7 @@
"h": 8,
"w": 12,
"x": 12,
- "y": 7
+ "y": 47
},
"id": 99,
"maxDataPoints": 100,
@@ -3100,6 +3226,7 @@
"showLegend": true
},
"tooltip": {
+ "maxHeight": 600,
"mode": "single",
"sort": "none"
}
@@ -3173,8 +3300,7 @@
"mode": "absolute",
"steps": [
{
- "color": "green",
- "value": null
+ "color": "green"
},
{
"color": "red",
@@ -3190,7 +3316,7 @@
"h": 8,
"w": 24,
"x": 0,
- "y": 15
+ "y": 55
},
"id": 24,
"options": {
@@ -3312,8 +3438,7 @@
"mode": "absolute",
"steps": [
{
- "color": "green",
- "value": null
+ "color": "green"
},
{
"color": "red",
@@ -3329,7 +3454,7 @@
"h": 8,
"w": 12,
"x": 0,
- "y": 23
+ "y": 63
},
"id": 4,
"options": {
@@ -3412,8 +3537,7 @@
"mode": "absolute",
"steps": [
{
- "color": "green",
- "value": null
+ "color": "green"
},
{
"color": "red",
@@ -3429,7 +3553,7 @@
"h": 8,
"w": 12,
"x": 12,
- "y": 23
+ "y": 63
},
"id": 96,
"options": {
@@ -3470,15 +3594,15 @@
"type": "row"
}
],
- "preload": false,
"refresh": "5s",
- "schemaVersion": 40,
+ "schemaVersion": 39,
"tags": [],
"templating": {
"list": [
{
"allValue": ".*",
"current": {
+ "selected": false,
"text": "All",
"value": "$__all"
},
@@ -3487,7 +3611,9 @@
"uid": "PBFA97CFB590B2093"
},
"definition": "label_values(service)",
+ "hide": 0,
"includeAll": true,
+ "multi": false,
"name": "service",
"options": [],
"query": {
@@ -3496,6 +3622,8 @@
},
"refresh": 1,
"regex": "",
+ "skipUrlSync": false,
+ "sort": 0,
"type": "query"
}
]
@@ -3504,6 +3632,7 @@
"from": "now-15m",
"to": "now"
},
+ "timeRangeUpdatedDuringEditOrView": false,
"timepicker": {
"refresh_intervals": [
"5s",
@@ -3514,6 +3643,6 @@
"timezone": "",
"title": "Services statistic",
"uid": "KVr-Vmpnz",
- "version": 4,
+ "version": 1,
"weekStart": ""
}
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 5724b2568..7c83195d1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -16,7 +16,7 @@
Application for resilience and highly-loaded applications course
- 2.2.0
+ 2.1.0
1.9.0
4.12.0
2.7.5
diff --git a/src/.DS_Store b/src/.DS_Store
new file mode 100644
index 000000000..254fc3aa6
Binary files /dev/null and b/src/.DS_Store differ
diff --git a/src/main/.DS_Store b/src/main/.DS_Store
new file mode 100644
index 000000000..a06cf1a73
Binary files /dev/null and b/src/main/.DS_Store differ
diff --git a/src/main/kotlin/.DS_Store b/src/main/kotlin/.DS_Store
new file mode 100644
index 000000000..f7103b774
Binary files /dev/null and b/src/main/kotlin/.DS_Store differ
diff --git a/src/main/kotlin/ru/.DS_Store b/src/main/kotlin/ru/.DS_Store
new file mode 100644
index 000000000..67775a855
Binary files /dev/null and b/src/main/kotlin/ru/.DS_Store differ
diff --git a/src/main/kotlin/ru/quipy/.DS_Store b/src/main/kotlin/ru/quipy/.DS_Store
new file mode 100644
index 000000000..4a9b381be
Binary files /dev/null and b/src/main/kotlin/ru/quipy/.DS_Store differ
diff --git a/src/main/kotlin/ru/quipy/OnlineShopApplication.kt b/src/main/kotlin/ru/quipy/OnlineShopApplication.kt
index 9ac22e094..41681afe8 100644
--- a/src/main/kotlin/ru/quipy/OnlineShopApplication.kt
+++ b/src/main/kotlin/ru/quipy/OnlineShopApplication.kt
@@ -3,12 +3,14 @@ package ru.quipy
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.boot.autoconfigure.SpringBootApplication
+import org.springframework.scheduling.annotation.EnableScheduling
import org.springframework.boot.runApplication
import ru.quipy.common.utils.NamedThreadFactory
import java.util.concurrent.Executors
@SpringBootApplication
+@EnableScheduling
class OnlineShopApplication {
val log: Logger = LoggerFactory.getLogger(OnlineShopApplication::class.java)
diff --git a/src/main/kotlin/ru/quipy/apigateway/APIController.kt b/src/main/kotlin/ru/quipy/apigateway/APIController.kt
index 6f23fa18d..e0ee9874e 100644
--- a/src/main/kotlin/ru/quipy/apigateway/APIController.kt
+++ b/src/main/kotlin/ru/quipy/apigateway/APIController.kt
@@ -6,6 +6,7 @@ import org.springframework.beans.factory.annotation.Autowired
import org.springframework.web.bind.annotation.*
import ru.quipy.orders.repository.OrderRepository
import ru.quipy.payments.logic.OrderPayer
+import ru.quipy.payments.logic.MetricsReporter
import java.util.*
@RestController
@@ -19,6 +20,9 @@ class APIController {
@Autowired
private lateinit var orderPayer: OrderPayer
+ @Autowired
+ private lateinit var metricsReporter: MetricsReporter
+
@PostMapping("/users")
fun createUser(@RequestBody req: CreateUserRequest): User {
return User(UUID.randomUUID(), req.name)
@@ -56,6 +60,7 @@ class APIController {
@PostMapping("/orders/{orderId}/payment")
fun payOrder(@PathVariable orderId: UUID, @RequestParam deadline: Long): PaymentSubmissionDto {
+ metricsReporter.incrementIncoming()
val paymentId = UUID.randomUUID()
val order = orderRepository.findById(orderId)?.let {
orderRepository.save(it.copy(status = OrderStatus.PAYMENT_IN_PROGRESS))
diff --git a/src/main/kotlin/ru/quipy/payments/.DS_Store b/src/main/kotlin/ru/quipy/payments/.DS_Store
new file mode 100644
index 000000000..79ead5ce5
Binary files /dev/null and b/src/main/kotlin/ru/quipy/payments/.DS_Store differ
diff --git a/src/main/kotlin/ru/quipy/payments/config/PaymentAccountsConfig.kt b/src/main/kotlin/ru/quipy/payments/config/PaymentAccountsConfig.kt
index eceb90cff..0bb510f43 100644
--- a/src/main/kotlin/ru/quipy/payments/config/PaymentAccountsConfig.kt
+++ b/src/main/kotlin/ru/quipy/payments/config/PaymentAccountsConfig.kt
@@ -6,6 +6,7 @@ import com.fasterxml.jackson.module.kotlin.registerKotlinModule
import org.springframework.beans.factory.annotation.Value
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
+import ru.quipy.payments.logic.PaymentRateLimiterFactory
import ru.quipy.core.EventSourcingService
import ru.quipy.payments.api.PaymentAggregate
import ru.quipy.payments.logic.*
@@ -36,7 +37,10 @@ class PaymentAccountsConfig {
lateinit var allowedAccounts: List
@Bean
- fun accountAdapters(paymentService: EventSourcingService): List {
+ fun accountAdapters(
+ paymentService: ru.quipy.core.EventSourcingService,
+ metricsReporter: MetricsReporter
+ ): List {
val request = HttpRequest.newBuilder()
.uri(URI("http://${paymentProviderHostPort}/external/accounts?serviceName=$serviceName&token=$token"))
.GET()
@@ -57,7 +61,9 @@ class PaymentAccountsConfig {
it,
paymentService,
paymentProviderHostPort,
- token
+ token,
+ PaymentRateLimiterFactory(),
+ metricsReporter
)
}
}
diff --git a/src/main/kotlin/ru/quipy/payments/logic/MetricsReporter.kt b/src/main/kotlin/ru/quipy/payments/logic/MetricsReporter.kt
new file mode 100644
index 000000000..01b62490e
--- /dev/null
+++ b/src/main/kotlin/ru/quipy/payments/logic/MetricsReporter.kt
@@ -0,0 +1,80 @@
+package ru.quipy.payments.logic
+
+import io.micrometer.core.instrument.Counter
+import io.micrometer.core.instrument.MeterRegistry
+import org.slf4j.LoggerFactory
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.scheduling.annotation.Scheduled
+import org.springframework.stereotype.Component
+import java.util.concurrent.TimeUnit
+import java.util.concurrent.atomic.AtomicLong
+
+@Component
+class MetricsReporter {
+
+ private val logger = LoggerFactory.getLogger(MetricsReporter::class.java)
+
+ private val incomingRequests = AtomicLong(0)
+ private val outgoingRequests = AtomicLong(0)
+ private val completedRequests = AtomicLong(0)
+ private val failedRequests = AtomicLong(0)
+
+ @Autowired
+ private lateinit var meterRegistry: MeterRegistry
+
+ private lateinit var incomingCounter: Counter
+ private lateinit var outgoingCounter: Counter
+ private lateinit var completedCounter: Counter
+ private lateinit var failedCounter: Counter
+
+ @Autowired
+ fun initMetrics() {
+ incomingCounter = Counter.builder("payment.requests.incoming")
+ .description("Total incoming payment requests")
+ .register(meterRegistry)
+
+ outgoingCounter = Counter.builder("payment.requests.outgoing")
+ .description("Total outgoing payment requests to external systems")
+ .register(meterRegistry)
+
+ completedCounter = Counter.builder("payment.requests.completed")
+ .description("Total completed payment requests")
+ .register(meterRegistry)
+
+ failedCounter = Counter.builder("payment.requests.failed")
+ .description("Total failed payment requests")
+ .register(meterRegistry)
+ }
+
+ fun incrementIncoming() {
+ incomingRequests.incrementAndGet()
+ incomingCounter.increment()
+ }
+
+ fun incrementOutgoing() {
+ outgoingRequests.incrementAndGet()
+ outgoingCounter.increment()
+ }
+
+ fun incrementCompleted() {
+ completedRequests.incrementAndGet()
+ completedCounter.increment()
+ }
+
+ fun incrementFailed() {
+ failedRequests.incrementAndGet()
+ failedCounter.increment()
+ }
+
+ @Scheduled(fixedRate = 10, timeUnit = TimeUnit.SECONDS)
+ fun reportMetrics() {
+ val incoming = incomingRequests.get()
+ val outgoing = outgoingRequests.get()
+ val completed = completedRequests.get()
+ val failed = failedRequests.get()
+
+ logger.info(
+ "METRICS | Incoming: $incoming | Outgoing: $outgoing | Completed: $completed | Failed: $failed"
+ )
+ }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/ru/quipy/payments/logic/OrderPayer.kt b/src/main/kotlin/ru/quipy/payments/logic/OrderPayer.kt
index a5909b85b..095db057d 100644
--- a/src/main/kotlin/ru/quipy/payments/logic/OrderPayer.kt
+++ b/src/main/kotlin/ru/quipy/payments/logic/OrderPayer.kt
@@ -26,6 +26,9 @@ class OrderPayer {
@Autowired
private lateinit var paymentService: PaymentService
+ @Autowired
+ private lateinit var metricsReporter: MetricsReporter
+
private val paymentExecutor = ThreadPoolExecutor(
16,
16,
diff --git a/src/main/kotlin/ru/quipy/payments/logic/PaymentExternalServiceImpl.kt b/src/main/kotlin/ru/quipy/payments/logic/PaymentExternalServiceImpl.kt
index 5cb12106a..62d4bd1b2 100644
--- a/src/main/kotlin/ru/quipy/payments/logic/PaymentExternalServiceImpl.kt
+++ b/src/main/kotlin/ru/quipy/payments/logic/PaymentExternalServiceImpl.kt
@@ -6,11 +6,15 @@ import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody
import org.slf4j.LoggerFactory
+import org.springframework.beans.factory.annotation.Autowired
+import ru.quipy.payments.logic.PaymentRateLimiterFactory
import ru.quipy.core.EventSourcingService
import ru.quipy.payments.api.PaymentAggregate
import java.net.SocketTimeoutException
import java.time.Duration
import java.util.*
+import java.util.concurrent.Executors
+import java.util.concurrent.atomic.AtomicLong
// Advice: always treat time as a Duration
@@ -19,11 +23,12 @@ class PaymentExternalSystemAdapterImpl(
private val paymentESService: EventSourcingService,
private val paymentProviderHostPort: String,
private val token: String,
+ private val rateLimiterFactory: PaymentRateLimiterFactory,
+ private val metricsReporter: MetricsReporter
) : PaymentExternalSystemAdapter {
companion object {
val logger = LoggerFactory.getLogger(PaymentExternalSystemAdapter::class.java)
-
val emptyBody = RequestBody.create(null, ByteArray(0))
val mapper = ObjectMapper().registerKotlinModule()
}
@@ -33,10 +38,27 @@ class PaymentExternalSystemAdapterImpl(
private val requestAverageProcessingTime = properties.averageProcessingTime
private val rateLimitPerSec = properties.rateLimitPerSec
private val parallelRequests = properties.parallelRequests
+ private val rateLimiter by lazy {
+ rateLimiterFactory.getRateLimiterForAccount(accountName, (rateLimitPerSec * 0.9).toInt())
+ }
+ private val paymentExecutor = Executors.newFixedThreadPool(parallelRequests)
private val client = OkHttpClient.Builder().build()
override fun performPaymentAsync(paymentId: UUID, amount: Int, paymentStartedAt: Long, deadline: Long) {
+ paymentExecutor.submit {
+ try {
+ metricsReporter.incrementOutgoing()
+ rateLimiter.tickBlocking()
+
+ executePayment(paymentId, amount, paymentStartedAt, deadline)
+ } catch (e: Exception) {
+ logger.error("[$accountName] Failed to process payment $paymentId", e)
+ }
+ }
+ }
+
+ private fun executePayment(paymentId: UUID, amount: Int, paymentStartedAt: Long, deadline: Long) {
logger.warn("[$accountName] Submitting payment request for payment $paymentId")
val transactionId = UUID.randomUUID()
@@ -70,6 +92,12 @@ class PaymentExternalSystemAdapterImpl(
paymentESService.update(paymentId) {
it.logProcessing(body.result, now(), transactionId, reason = body.message)
}
+
+ if (body.result) {
+ metricsReporter.incrementCompleted()
+ } else {
+ metricsReporter.incrementFailed()
+ }
}
} catch (e: Exception) {
when (e) {
@@ -88,6 +116,7 @@ class PaymentExternalSystemAdapterImpl(
}
}
}
+ metricsReporter.incrementFailed()
}
}
@@ -96,7 +125,6 @@ class PaymentExternalSystemAdapterImpl(
override fun isEnabled() = properties.enabled
override fun name() = properties.accountName
-
}
-public fun now() = System.currentTimeMillis()
\ No newline at end of file
+fun now() = System.currentTimeMillis()
\ No newline at end of file
diff --git a/src/main/kotlin/ru/quipy/payments/logic/PaymentRateLimiterFactory.kt b/src/main/kotlin/ru/quipy/payments/logic/PaymentRateLimiterFactory.kt
new file mode 100644
index 000000000..5a6bded01
--- /dev/null
+++ b/src/main/kotlin/ru/quipy/payments/logic/PaymentRateLimiterFactory.kt
@@ -0,0 +1,21 @@
+package ru.quipy.payments.logic
+
+import org.springframework.stereotype.Component
+import ru.quipy.common.utils.SlidingWindowRateLimiter
+import java.time.Duration
+import java.util.concurrent.ConcurrentHashMap
+
+@Component
+class PaymentRateLimiterFactory {
+
+ private val rateLimiters = ConcurrentHashMap()
+
+ fun getRateLimiterForAccount(accountName: String, rateLimitPerSec: Int): SlidingWindowRateLimiter {
+ return rateLimiters.computeIfAbsent(accountName) {
+ SlidingWindowRateLimiter(
+ rate = rateLimitPerSec.toLong(),
+ window = Duration.ofSeconds(1)
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/ru/quipy/payments/logic/PaymentServiceImpl.kt b/src/main/kotlin/ru/quipy/payments/logic/PaymentServiceImpl.kt
index 1c24e5a72..80d184523 100644
--- a/src/main/kotlin/ru/quipy/payments/logic/PaymentServiceImpl.kt
+++ b/src/main/kotlin/ru/quipy/payments/logic/PaymentServiceImpl.kt
@@ -21,7 +21,11 @@ class PaymentSystemImpl(
val logger = LoggerFactory.getLogger(PaymentSystemImpl::class.java)
}
+ @Autowired
+ private lateinit var metricsReporter: MetricsReporter
+
override fun submitPaymentRequest(paymentId: UUID, amount: Int, paymentStartedAt: Long, deadline: Long) {
+ metricsReporter.incrementIncoming()
for (account in paymentAccounts) {
account.performPaymentAsync(paymentId, amount, paymentStartedAt, deadline)
}
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index 33d51a58b..70328e2c4 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -26,5 +26,5 @@ management.endpoints.web.exposure.include=info,health,prometheus,metrics
payment.service-name=${PAYMENT_SERVICE_NAME}
payment.token=${PAYMENT_TOKEN}
-payment.accounts=${PAYMENT_ACCOUNTS:acc-12,acc-20}
+payment.accounts=${PAYMENT_ACCOUNTS:acc-5}
payment.hostPort=${PAYMENT_HOST:localhost}:${PAYMENT_PORT:1234}
\ No newline at end of file