Commit 2c02406ee5f41b08e655b634dd9871403f67149d
Committed by
GitHub
1 parent
a868f006
Merge with master. AlarmRepository.findAlarms is failing (#2663)
* Merge with master. AlarmRepository.findAlarms is failing * Fix Alarm repository. Add queue type list select. Co-authored-by: Igor Kulikov <ikulikov@thingsboard.io>
Showing
26 changed files
with
2456 additions
and
1316 deletions
Too many changes to show.
To preserve performance only 26 of 471 files are displayed.
1 | +{ | ||
2 | + "title": "Gateways", | ||
3 | + "configuration": { | ||
4 | + "widgets": { | ||
5 | + "94715984-ae74-76e4-20b7-2f956b01ed80": { | ||
6 | + "isSystemType": true, | ||
7 | + "bundleAlias": "entity_admin_widgets", | ||
8 | + "typeAlias": "device_admin_table2", | ||
9 | + "type": "latest", | ||
10 | + "title": "New widget", | ||
11 | + "sizeX": 24, | ||
12 | + "sizeY": 12, | ||
13 | + "config": { | ||
14 | + "timewindow": { | ||
15 | + "realtime": { | ||
16 | + "interval": 1000, | ||
17 | + "timewindowMs": 86400000 | ||
18 | + }, | ||
19 | + "aggregation": { | ||
20 | + "type": "NONE", | ||
21 | + "limit": 200 | ||
22 | + } | ||
23 | + }, | ||
24 | + "showTitle": true, | ||
25 | + "backgroundColor": "rgb(255, 255, 255)", | ||
26 | + "color": "rgba(0, 0, 0, 0.87)", | ||
27 | + "padding": "4px", | ||
28 | + "settings": { | ||
29 | + "enableSearch": true, | ||
30 | + "displayPagination": true, | ||
31 | + "defaultPageSize": 10, | ||
32 | + "defaultSortOrder": "entityName", | ||
33 | + "displayEntityName": true, | ||
34 | + "displayEntityType": false, | ||
35 | + "entitiesTitle": "List of gateways", | ||
36 | + "enableSelectColumnDisplay": true, | ||
37 | + "displayEntityLabel": false, | ||
38 | + "entityNameColumnTitle": "Gateway Name" | ||
39 | + }, | ||
40 | + "title": "Devices gateway table", | ||
41 | + "dropShadow": true, | ||
42 | + "enableFullscreen": true, | ||
43 | + "titleStyle": { | ||
44 | + "fontSize": "16px", | ||
45 | + "fontWeight": 400, | ||
46 | + "padding": "5px 10px 5px 10px" | ||
47 | + }, | ||
48 | + "useDashboardTimewindow": false, | ||
49 | + "showLegend": false, | ||
50 | + "datasources": [ | ||
51 | + { | ||
52 | + "type": "entity", | ||
53 | + "dataKeys": [ | ||
54 | + { | ||
55 | + "name": "active", | ||
56 | + "type": "attribute", | ||
57 | + "label": "Active", | ||
58 | + "color": "#2196f3", | ||
59 | + "settings": { | ||
60 | + "columnWidth": "0px", | ||
61 | + "useCellStyleFunction": true, | ||
62 | + "useCellContentFunction": true, | ||
63 | + "cellContentFunction": "value = '⬤';\nreturn value;", | ||
64 | + "cellStyleFunction": "var color;\nif (value == 'false') {\n color = '#EB5757';\n} else {\n color = '#27AE60';\n}\nreturn {\n color: color,\n fontSize: '18px'\n};" | ||
65 | + }, | ||
66 | + "_hash": 0.3646047595211721 | ||
67 | + }, | ||
68 | + { | ||
69 | + "name": "eventsSent", | ||
70 | + "type": "timeseries", | ||
71 | + "label": "Sent", | ||
72 | + "color": "#4caf50", | ||
73 | + "settings": { | ||
74 | + "columnWidth": "0px", | ||
75 | + "useCellStyleFunction": false, | ||
76 | + "useCellContentFunction": false | ||
77 | + }, | ||
78 | + "_hash": 0.7235710720767985 | ||
79 | + }, | ||
80 | + { | ||
81 | + "name": "eventsProduced", | ||
82 | + "type": "timeseries", | ||
83 | + "label": "Events", | ||
84 | + "color": "#f44336", | ||
85 | + "settings": { | ||
86 | + "columnWidth": "0px", | ||
87 | + "useCellStyleFunction": false, | ||
88 | + "useCellContentFunction": false | ||
89 | + }, | ||
90 | + "_hash": 0.5085933386303254 | ||
91 | + }, | ||
92 | + { | ||
93 | + "name": "LOGS", | ||
94 | + "type": "timeseries", | ||
95 | + "label": "Latest log", | ||
96 | + "color": "#ffc107", | ||
97 | + "settings": { | ||
98 | + "columnWidth": "0px", | ||
99 | + "useCellStyleFunction": false, | ||
100 | + "useCellContentFunction": false | ||
101 | + }, | ||
102 | + "_hash": 0.3504240371585048, | ||
103 | + "postFuncBody": "if(value) {\n return value.substring(0, 31) + \"...\";\n} else {\n return '';\n}" | ||
104 | + }, | ||
105 | + { | ||
106 | + "name": "RemoteLoggingLevel", | ||
107 | + "type": "attribute", | ||
108 | + "label": "Log level", | ||
109 | + "color": "#607d8b", | ||
110 | + "settings": { | ||
111 | + "columnWidth": "0px", | ||
112 | + "useCellStyleFunction": false, | ||
113 | + "useCellContentFunction": false | ||
114 | + }, | ||
115 | + "_hash": 0.9785994222542516 | ||
116 | + } | ||
117 | + ], | ||
118 | + "entityAliasId": "3e0f533a-0db1-3292-184f-06e73535061a" | ||
119 | + } | ||
120 | + ], | ||
121 | + "showTitleIcon": true, | ||
122 | + "titleIcon": "list", | ||
123 | + "iconColor": "rgba(0, 0, 0, 0.87)", | ||
124 | + "iconSize": "24px", | ||
125 | + "titleTooltip": "List device", | ||
126 | + "widgetStyle": {}, | ||
127 | + "displayTimewindow": true, | ||
128 | + "actions": { | ||
129 | + "headerButton": [ | ||
130 | + { | ||
131 | + "id": "70837a9d-c3de-a9a7-03c5-dccd14998758", | ||
132 | + "name": "Add device", | ||
133 | + "icon": "add", | ||
134 | + "type": "customPretty", | ||
135 | + "customHtml": "<md-dialog aria-label=\"Add entity\" style=\"width: 480px\">\n <form name=\"addDeviceForm\" ng-submit=\"vm.save()\">\n <md-toolbar>\n <div class=\"md-toolbar-tools\">\n <h2>Add device</h2>\n <span flex></span>\n <md-button class=\"md-icon-button\" ng-click=\"vm.cancel()\">\n <ng-md-icon icon=\"close\" aria-label=\"Close\"></ng-md-icon>\n </md-button>\n </div>\n </md-toolbar>\n <md-progress-linear class=\"md-warn\" md-mode=\"indeterminate\" ng-disabled=\"!$root.loading && !vm.loading\" ng-show=\"$root.loading || vm.loading\"></md-progress-linear>\n <span style=\"min-height: 5px;\" flex=\"\" ng-show=\"!$root.loading && !vm.loading\"></span>\n <md-dialog-content>\n <div class=\"md-dialog-content\">\n <fieldset ng-disabled=\"$root.loading || vm.loading\">\n <md-input-container flex class=\"md-block\">\n <label>Device name</label>\n <input ng-model=\"vm.deviceName\" name=deviceName required>\n <div ng-messages=\"addDeviceForm.deviceName.$error\">\n <div ng-message=\"required\">Device name is required.</div>\n </div>\n </md-input-container>\n <div flex layout=\"row\">\n <md-input-container flex=\"50\" class=\"md-block\">\n <label>Latitude</label>\n <input type=\"number\" step=\"any\" name=\"latitude\" ng-model=\"vm.attributes.latitude\">\n </md-input-container>\n <md-input-container flex=\"50\" class=\"md-block\">\n <label>Longitude</label>\n <input type=\"number\" step=\"any\" name=\"longitude\" ng-model=\"vm.attributes.longitude\">\n </md-input-container>\n </div>\n <md-input-container class=\"md-block\">\n <label>Label</label>\n <input name=\"deviceLabel\" ng-model=\"vm.deviceLabel\">\n </md-input-container>\n </fieldset>\n </div>\n </md-dialog-content>\n <md-dialog-actions>\n <md-button type=\"submit\" ng-disabled=\"vm.loading || addDeviceForm.$invalid || !addDeviceForm.$dirty\" class=\"md-raised md-primary\">Create</md-button>\n <md-button ng-click=\"vm.cancel()\" class=\"md-primary\">Cancel</md-button>\n </md-dialog-actions>\n </form>\n</md-dialog>\n", | ||
136 | + "customCss": "", | ||
137 | + "customFunction": "let $injector = widgetContext.$scope.$injector;\nlet $mdDialog = $injector.get('$mdDialog'),\n $document = $injector.get('$document'),\n $q = $injector.get('$q'),\n $rootScope = $injector.get('$rootScope'),\n types = $injector.get('types'),\n deviceService = $injector.get('deviceService'),\n attributeService = $injector.get('attributeService');\n\nopenAddDeviceDialog();\n\nfunction openAddDeviceDialog() {\n $mdDialog.show({\n controller: ['$scope', '$mdDialog',\n AddDeviceDialogController\n ],\n controllerAs: 'vm',\n template: htmlTemplate,\n parent: angular.element($document[0].body),\n targetEvent: $event,\n multiple: true,\n clickOutsideToClose: false\n });\n}\n\nfunction AddDeviceDialogController($scope, $mdDialog) {\n let vm = this;\n vm.types = types;\n vm.attributes = {};\n vm.deviceType = \"gateway\";\n\n vm.cancel = () => {\n $mdDialog.hide();\n };\n\n vm.save = () => {\n vm.loading = true;\n $scope.addDeviceForm.$setPristine();\n let device = {\n additionalInfo: {gateway: true},\n name: vm.deviceName,\n type: vm.deviceType,\n label: vm.deviceLabel\n };\n deviceService.saveDevice(device).then(\n (device) => {\n saveAttributes(device.id).then(\n () => {\n vm.loading = false;\n updateAliasData();\n $mdDialog.hide();\n }\n );\n },\n () => {\n vm.loading = false;\n }\n );\n };\n\n function saveAttributes(entityId) {\n let attributesArray = [];\n for (let key in vm.attributes) {\n attributesArray.push({\n key: key,\n value: vm.attributes[key]\n });\n }\n if (attributesArray.length > 0) {\n return attributeService.saveEntityAttributes(\n entityId.entityType, entityId.id,\n \"SERVER_SCOPE\", attributesArray);\n } else {\n return $q.when([]);\n }\n }\n\n function updateAliasData() {\n let aliasIds = [];\n for (let id in widgetContext.aliasController\n .resolvedAliases) {\n aliasIds.push(id);\n }\n let tasks = [];\n aliasIds.forEach((aliasId) => {\n widgetContext.aliasController\n .setAliasUnresolved(aliasId);\n tasks.push(widgetContext.aliasController\n .getAliasInfo(aliasId));\n });\n $q.all(tasks).then(() => {\n $rootScope.$broadcast(\n 'widgetForceReInit');\n });\n }\n}" | ||
138 | + } | ||
139 | + ], | ||
140 | + "actionCellButton": [ | ||
141 | + { | ||
142 | + "id": "78845501-234e-a452-6819-82b5b776e99f", | ||
143 | + "name": "Configuration", | ||
144 | + "icon": "settings", | ||
145 | + "type": "openDashboardState", | ||
146 | + "targetDashboardStateId": "__entityname__config", | ||
147 | + "openRightLayout": false, | ||
148 | + "setEntityId": true | ||
149 | + }, | ||
150 | + { | ||
151 | + "id": "f6ffdba8-e40f-2b8d-851b-f5ecaf18606b", | ||
152 | + "name": "Graphs", | ||
153 | + "icon": "show_chart", | ||
154 | + "type": "openDashboardState", | ||
155 | + "targetDashboardStateId": "__entityname_grafic", | ||
156 | + "setEntityId": true | ||
157 | + }, | ||
158 | + { | ||
159 | + "id": "242671f3-76c6-6982-7acc-6f12addf0ccc", | ||
160 | + "name": "Edit device", | ||
161 | + "icon": "edit", | ||
162 | + "type": "customPretty", | ||
163 | + "customHtml": "<md-dialog aria-label=\"Edit entity\" style=\"width: 480px\">\n <form name=\"editDeviceForm\" ng-submit=\"vm.save()\">\n <md-toolbar>\n <div class=\"md-toolbar-tools\">\n <h2>Edit device</h2>\n <span flex></span>\n <md-button class=\"md-icon-button\" ng-click=\"vm.cancel()\">\n <ng-md-icon icon=\"close\" aria-label=\"Close\"></ng-md-icon>\n </md-button>\n </div>\n </md-toolbar>\n <md-progress-linear class=\"md-warn\" md-mode=\"indeterminate\" ng-disabled=\"!$root.loading && !vm.loading\" ng-show=\"$root.loading || vm.loading\"></md-progress-linear>\n <span style=\"min-height: 5px;\" flex=\"\" ng-show=\"!$root.loading && !vm.loading\"></span>\n <md-dialog-content>\n <div class=\"md-dialog-content\">\n <fieldset ng-disabled=\"$root.loading || vm.loading\">\n <md-input-container flex class=\"md-block\">\n <label>Device name</label>\n <input ng-model=\"vm.device.name\" name=deviceName required>\n <div ng-messages=\"editDeviceForm.deviceName.$error\">\n <div ng-message=\"required\">Device name is required.</div>\n </div>\n </md-input-container>\n <!--<div flex layout=\"row\">-->\n <!--<tb-entity-subtype-autocomplete flex=\"50\"-->\n <!-- ng-disabled=\"true\"-->\n <!-- tb-required=\"true\"-->\n <!-- the-form=\"editDeviceForm\"-->\n <!-- ng-model=\"vm.device.type\"-->\n <!-- entity-type=\"vm.types.entityType.device\">-->\n <!--</tb-entity-subtype-autocomplete>-->\n <!-- <md-input-container flex=\"50\" class=\"md-block\">-->\n <!-- <label>Label</label>-->\n <!-- <input name=\"deviceLabel\" ng-model=\"vm.device.label\">-->\n <!-- </md-input-container>-->\n <!--</div>-->\n <div flex layout=\"row\">\n <md-input-container flex=\"50\" class=\"md-block\">\n <label>Latitude</label>\n <input type=\"number\" step=\"any\" name=\"latitude\" ng-model=\"vm.attributes.latitude\">\n </md-input-container>\n <md-input-container flex=\"50\" class=\"md-block\">\n <label>Longitude</label>\n <input type=\"number\" step=\"any\" name=\"longitude\" ng-model=\"vm.attributes.longitude\">\n </md-input-container>\n </div>\n <md-input-container class=\"md-block\">\n <label>Label</label>\n <input name=\"deviceLabel\" ng-model=\"vm.device.label\">\n </md-input-container>\n </fieldset>\n </div>\n </md-dialog-content>\n <md-dialog-actions>\n <md-button type=\"submit\" ng-disabled=\"vm.loading || editDeviceForm.$invalid || !editDeviceForm.$dirty\" class=\"md-raised md-primary\">Create</md-button>\n <md-button ng-click=\"vm.cancel()\" class=\"md-primary\">Cancel</md-button>\n </md-dialog-actions>\n </form>\n</md-dialog>", | ||
164 | + "customCss": "/*=======================================================================*/\n/*========== There are two examples: for edit and add entity ==========*/\n/*=======================================================================*/\n/*======================== Edit entity example ========================*/\n/*=======================================================================*/\n/*\n.edit-entity-form md-input-container {\n padding-right: 10px;\n}\n\n.edit-entity-form .boolean-value-input {\n padding-left: 5px;\n}\n\n.edit-entity-form .boolean-value-input .checkbox-label {\n margin-bottom: 8px;\n color: rgba(0,0,0,0.54);\n font-size: 12px;\n}\n\n.relations-list .header {\n padding-right: 5px;\n padding-bottom: 5px;\n padding-left: 5px;\n}\n\n.relations-list .header .cell {\n padding-right: 5px;\n padding-left: 5px;\n font-size: 12px;\n font-weight: 700;\n color: rgba(0, 0, 0, .54);\n white-space: nowrap;\n}\n\n.relations-list .body {\n padding-right: 5px;\n padding-bottom: 15px;\n padding-left: 5px;\n}\n\n.relations-list .body .row {\n padding-top: 5px;\n}\n\n.relations-list .body .cell {\n padding-right: 5px;\n padding-left: 5px;\n}\n\n.relations-list .body md-autocomplete-wrap md-input-container {\n height: 30px;\n}\n\n.relations-list .body .md-button {\n margin: 0;\n}\n\n.relations-list.old-relations tb-entity-select tb-entity-autocomplete button {\n display: none;\n} \n*/\n/*========================================================================*/\n/*========================= Add entity example =========================*/\n/*========================================================================*/\n/*\n.add-entity-form md-input-container {\n padding-right: 10px;\n}\n\n.add-entity-form .boolean-value-input {\n padding-left: 5px;\n}\n\n.add-entity-form .boolean-value-input .checkbox-label {\n margin-bottom: 8px;\n color: rgba(0,0,0,0.54);\n font-size: 12px;\n}\n\n.relations-list .header {\n padding-right: 5px;\n padding-bottom: 5px;\n padding-left: 5px;\n}\n\n.relations-list .header .cell {\n padding-right: 5px;\n padding-left: 5px;\n font-size: 12px;\n font-weight: 700;\n color: rgba(0, 0, 0, .54);\n white-space: nowrap;\n}\n\n.relations-list .body {\n padding-right: 5px;\n padding-bottom: 15px;\n padding-left: 5px;\n}\n\n.relations-list .body .row {\n padding-top: 5px;\n}\n\n.relations-list .body .cell {\n padding-right: 5px;\n padding-left: 5px;\n}\n\n.relations-list .body md-autocomplete-wrap md-input-container {\n height: 30px;\n}\n\n.relations-list .body .md-button {\n margin: 0;\n}\n*/\n", | ||
165 | + "customFunction": "let $injector = widgetContext.$scope.$injector;\nlet $mdDialog = $injector.get('$mdDialog'),\n $document = $injector.get('$document'),\n $q = $injector.get('$q'),\n $rootScope = $injector.get('$rootScope'),\n types = $injector.get('types'),\n deviceService = $injector.get('deviceService'),\n attributeService = $injector.get('attributeService');\n \nopenEditDeviceDialog();\n\nfunction openEditDeviceDialog() {\n $mdDialog.show({\n controller: ['$scope','$mdDialog', EditDeviceDialogController],\n controllerAs: 'vm',\n template: htmlTemplate,\n parent: angular.element($document[0].body),\n targetEvent: $event,\n multiple: true,\n clickOutsideToClose: false\n });\n}\n\nfunction EditDeviceDialogController($scope,$mdDialog) {\n let vm = this;\n vm.types = types;\n vm.loading = false;\n vm.attributes = {};\n \n getEntityInfo();\n \n function getEntityInfo() {\n vm.loading = true;\n deviceService.getDevice(entityId.id).then(\n (device) => {\n attributeService.getEntityAttributesValues(entityId.entityType, entityId.id, 'SERVER_SCOPE').then(\n (data) => {\n if (data.length) {\n getEntityAttributes(data);\n }\n vm.device = device;\n vm.loading = false;\n } \n );\n }\n )\n }\n \n vm.cancel = function() {\n $mdDialog.hide();\n };\n \n vm.save = () => {\n vm.loading = true;\n $scope.editDeviceForm.$setPristine();\n deviceService.saveDevice(vm.device).then(\n () => {\n saveAttributes().then(\n () => {\n updateAliasData();\n vm.loading = false;\n $mdDialog.hide();\n }\n );\n },\n () => {\n vm.loading = false;\n }\n );\n }\n \n function getEntityAttributes(attributes) {\n for (let i = 0; i < attributes.length; i++) {\n vm.attributes[attributes[i].key] = attributes[i].value; \n }\n }\n \n function saveAttributes() {\n let attributesArray = [];\n for (let key in vm.attributes) {\n attributesArray.push({key: key, value: vm.attributes[key]});\n }\n if (attributesArray.length > 0) {\n return attributeService.saveEntityAttributes(entityId.entityType, entityId.id, \"SERVER_SCOPE\", attributesArray);\n } else {\n return $q.when([]);\n }\n }\n \n function updateAliasData() {\n let aliasIds = [];\n for (let id in widgetContext.aliasController.resolvedAliases) {\n aliasIds.push(id);\n }\n let tasks = [];\n aliasIds.forEach((aliasId) => {\n widgetContext.aliasController.setAliasUnresolved(aliasId);\n tasks.push(widgetContext.aliasController.getAliasInfo(aliasId));\n });\n console.log(widgetContext);\n $q.all(tasks).then(() => {\n $rootScope.$broadcast('widgetForceReInit');\n });\n }\n}\n" | ||
166 | + }, | ||
167 | + { | ||
168 | + "id": "862ec2b7-fbcf-376e-f85f-b77c07f36efa", | ||
169 | + "name": "Delete device", | ||
170 | + "icon": "delete", | ||
171 | + "type": "custom", | ||
172 | + "customFunction": "let $injector = widgetContext.$scope.$injector;\nlet $mdDialog = $injector.get('$mdDialog'),\n $document = $injector.get('$document'),\n types = $injector.get('types'),\n deviceService = $injector.get('deviceService'),\n $rootScope = $injector.get('$rootScope'),\n $q = $injector.get('$q');\n\nopenDeleteDeviceDialog();\n\nfunction openDeleteDeviceDialog() {\n let title = \"Are you sure you want to delete the device \" + entityName + \"?\";\n let content = \"Be careful, after the confirmation, the device and all related data will become unrecoverable!\";\n let confirm = $mdDialog.confirm()\n .targetEvent($event)\n .title(title)\n .htmlContent(content)\n .ariaLabel(title)\n .cancel('Cancel')\n .ok('Delete');\n $mdDialog.show(confirm).then(() => {\n deleteDevice();\n })\n}\n\nfunction deleteDevice() {\n deviceService.deleteDevice(entityId.id).then(\n () => {\n updateAliasData();\n }\n );\n}\n\nfunction updateAliasData() {\n let aliasIds = [];\n for (let id in widgetContext.aliasController.resolvedAliases) {\n aliasIds.push(id);\n }\n let tasks = [];\n aliasIds.forEach((aliasId) => {\n widgetContext.aliasController.setAliasUnresolved(aliasId);\n tasks.push(widgetContext.aliasController.getAliasInfo(aliasId));\n });\n $q.all(tasks).then(() => {\n $rootScope.$broadcast('entityAliasesChanged', aliasIds);\n });\n}" | ||
173 | + } | ||
174 | + ], | ||
175 | + "rowClick": [ | ||
176 | + { | ||
177 | + "id": "ad5fc7e1-5e60-e056-6940-a75a383466a1", | ||
178 | + "name": "to_entityname__config", | ||
179 | + "icon": "more_horiz", | ||
180 | + "type": "openDashboardState", | ||
181 | + "targetDashboardStateId": "__entityname__config", | ||
182 | + "setEntityId": true, | ||
183 | + "stateEntityParamName": "" | ||
184 | + } | ||
185 | + ] | ||
186 | + } | ||
187 | + }, | ||
188 | + "id": "94715984-ae74-76e4-20b7-2f956b01ed80" | ||
189 | + }, | ||
190 | + "eadabbc7-519e-76fc-ba10-b3fe8c18da10": { | ||
191 | + "isSystemType": true, | ||
192 | + "bundleAlias": "cards", | ||
193 | + "typeAlias": "timeseries_table", | ||
194 | + "type": "timeseries", | ||
195 | + "title": "New widget", | ||
196 | + "sizeX": 14, | ||
197 | + "sizeY": 13, | ||
198 | + "config": { | ||
199 | + "datasources": [ | ||
200 | + { | ||
201 | + "type": "entity", | ||
202 | + "dataKeys": [ | ||
203 | + { | ||
204 | + "name": "LOGS", | ||
205 | + "type": "timeseries", | ||
206 | + "label": "LOGS", | ||
207 | + "color": "#2196f3", | ||
208 | + "settings": { | ||
209 | + "useCellStyleFunction": false, | ||
210 | + "useCellContentFunction": false | ||
211 | + }, | ||
212 | + "_hash": 0.3496649158709739, | ||
213 | + "postFuncBody": "return value.replace(/ - (.*) - \\[/gi, ' - <b style=\"color:#0f0;\">$1</b> - [');" | ||
214 | + } | ||
215 | + ], | ||
216 | + "entityAliasId": "b2487e75-2fa4-f211-142c-434dfd50c70c" | ||
217 | + } | ||
218 | + ], | ||
219 | + "timewindow": { | ||
220 | + "realtime": { | ||
221 | + "interval": 1000, | ||
222 | + "timewindowMs": 2592000000 | ||
223 | + }, | ||
224 | + "aggregation": { | ||
225 | + "type": "NONE", | ||
226 | + "limit": 200 | ||
227 | + } | ||
228 | + }, | ||
229 | + "showTitle": true, | ||
230 | + "backgroundColor": "rgb(255, 255, 255)", | ||
231 | + "color": "rgba(0, 0, 0, 0.87)", | ||
232 | + "padding": "8px", | ||
233 | + "settings": { | ||
234 | + "showTimestamp": true, | ||
235 | + "displayPagination": true, | ||
236 | + "defaultPageSize": 10 | ||
237 | + }, | ||
238 | + "title": "Debug events (logs)", | ||
239 | + "dropShadow": true, | ||
240 | + "enableFullscreen": true, | ||
241 | + "titleStyle": { | ||
242 | + "fontSize": "16px", | ||
243 | + "fontWeight": 400 | ||
244 | + }, | ||
245 | + "useDashboardTimewindow": false, | ||
246 | + "showLegend": false, | ||
247 | + "widgetStyle": {}, | ||
248 | + "actions": {}, | ||
249 | + "showTitleIcon": false, | ||
250 | + "titleIcon": null, | ||
251 | + "iconColor": "rgba(0, 0, 0, 0.87)", | ||
252 | + "iconSize": "24px", | ||
253 | + "titleTooltip": "", | ||
254 | + "displayTimewindow": true | ||
255 | + }, | ||
256 | + "id": "eadabbc7-519e-76fc-ba10-b3fe8c18da10" | ||
257 | + }, | ||
258 | + "f928afc4-30d1-8d0c-e3cf-777f9f9d1155": { | ||
259 | + "isSystemType": true, | ||
260 | + "bundleAlias": "charts", | ||
261 | + "typeAlias": "basic_timeseries", | ||
262 | + "type": "timeseries", | ||
263 | + "title": "New widget", | ||
264 | + "sizeX": 17, | ||
265 | + "sizeY": 4, | ||
266 | + "config": { | ||
267 | + "datasources": [ | ||
268 | + { | ||
269 | + "type": "entity", | ||
270 | + "dataKeys": [ | ||
271 | + { | ||
272 | + "name": "opcuaEventsProduced", | ||
273 | + "type": "timeseries", | ||
274 | + "label": "opcuaEventsProduced", | ||
275 | + "color": "#2196f3", | ||
276 | + "settings": { | ||
277 | + "excludeFromStacking": false, | ||
278 | + "hideDataByDefault": false, | ||
279 | + "disableDataHiding": false, | ||
280 | + "removeFromLegend": false, | ||
281 | + "showLines": true, | ||
282 | + "fillLines": false, | ||
283 | + "showPoints": false, | ||
284 | + "showPointShape": "circle", | ||
285 | + "pointShapeFormatter": "var size = radius * Math.sqrt(Math.PI) / 2;\nctx.moveTo(x - size, y - size);\nctx.lineTo(x + size, y + size);\nctx.moveTo(x - size, y + size);\nctx.lineTo(x + size, y - size);", | ||
286 | + "showPointsLineWidth": 5, | ||
287 | + "showPointsRadius": 3, | ||
288 | + "tooltipValueFormatter": "", | ||
289 | + "showSeparateAxis": false, | ||
290 | + "axisTitle": "", | ||
291 | + "axisPosition": "left", | ||
292 | + "axisTicksFormatter": "", | ||
293 | + "comparisonSettings": { | ||
294 | + "showValuesForComparison": true, | ||
295 | + "comparisonValuesLabel": "", | ||
296 | + "color": "" | ||
297 | + } | ||
298 | + }, | ||
299 | + "_hash": 0.1477920581839779 | ||
300 | + }, | ||
301 | + { | ||
302 | + "name": "opcuaEventsSent", | ||
303 | + "type": "timeseries", | ||
304 | + "label": "opcuaEventsSent", | ||
305 | + "color": "#4caf50", | ||
306 | + "settings": { | ||
307 | + "excludeFromStacking": false, | ||
308 | + "hideDataByDefault": false, | ||
309 | + "disableDataHiding": false, | ||
310 | + "removeFromLegend": false, | ||
311 | + "showLines": true, | ||
312 | + "fillLines": false, | ||
313 | + "showPoints": false, | ||
314 | + "showPointShape": "circle", | ||
315 | + "pointShapeFormatter": "var size = radius * Math.sqrt(Math.PI) / 2;\nctx.moveTo(x - size, y - size);\nctx.lineTo(x + size, y + size);\nctx.moveTo(x - size, y + size);\nctx.lineTo(x + size, y - size);", | ||
316 | + "showPointsLineWidth": 5, | ||
317 | + "showPointsRadius": 3, | ||
318 | + "tooltipValueFormatter": "", | ||
319 | + "showSeparateAxis": false, | ||
320 | + "axisTitle": "", | ||
321 | + "axisPosition": "left", | ||
322 | + "axisTicksFormatter": "", | ||
323 | + "comparisonSettings": { | ||
324 | + "showValuesForComparison": true, | ||
325 | + "comparisonValuesLabel": "", | ||
326 | + "color": "" | ||
327 | + } | ||
328 | + }, | ||
329 | + "_hash": 0.6500957113784758 | ||
330 | + } | ||
331 | + ], | ||
332 | + "entityAliasId": "b2487e75-2fa4-f211-142c-434dfd50c70c" | ||
333 | + } | ||
334 | + ], | ||
335 | + "timewindow": { | ||
336 | + "realtime": { | ||
337 | + "interval": 1000, | ||
338 | + "timewindowMs": 120000 | ||
339 | + }, | ||
340 | + "aggregation": { | ||
341 | + "type": "NONE", | ||
342 | + "limit": 25000 | ||
343 | + }, | ||
344 | + "hideInterval": false, | ||
345 | + "hideAggregation": false | ||
346 | + }, | ||
347 | + "showTitle": true, | ||
348 | + "backgroundColor": "#fff", | ||
349 | + "color": "rgba(0, 0, 0, 0.87)", | ||
350 | + "padding": "8px", | ||
351 | + "settings": { | ||
352 | + "shadowSize": 4, | ||
353 | + "fontColor": "#545454", | ||
354 | + "fontSize": 10, | ||
355 | + "xaxis": { | ||
356 | + "showLabels": true, | ||
357 | + "color": "#545454" | ||
358 | + }, | ||
359 | + "yaxis": { | ||
360 | + "showLabels": true, | ||
361 | + "color": "#545454" | ||
362 | + }, | ||
363 | + "grid": { | ||
364 | + "color": "#545454", | ||
365 | + "tickColor": "#DDDDDD", | ||
366 | + "verticalLines": true, | ||
367 | + "horizontalLines": true, | ||
368 | + "outlineWidth": 1 | ||
369 | + }, | ||
370 | + "stack": false, | ||
371 | + "tooltipIndividual": false, | ||
372 | + "timeForComparison": "months", | ||
373 | + "xaxisSecond": { | ||
374 | + "axisPosition": "top", | ||
375 | + "showLabels": true | ||
376 | + } | ||
377 | + }, | ||
378 | + "title": "Real time information", | ||
379 | + "dropShadow": true, | ||
380 | + "enableFullscreen": true, | ||
381 | + "titleStyle": { | ||
382 | + "fontSize": "16px", | ||
383 | + "fontWeight": 400 | ||
384 | + }, | ||
385 | + "mobileHeight": null, | ||
386 | + "showTitleIcon": false, | ||
387 | + "titleIcon": null, | ||
388 | + "iconColor": "rgba(0, 0, 0, 0.87)", | ||
389 | + "iconSize": "24px", | ||
390 | + "titleTooltip": "", | ||
391 | + "widgetStyle": {}, | ||
392 | + "useDashboardTimewindow": false, | ||
393 | + "displayTimewindow": true, | ||
394 | + "showLegend": true, | ||
395 | + "legendConfig": { | ||
396 | + "direction": "column", | ||
397 | + "position": "right", | ||
398 | + "showMin": true, | ||
399 | + "showMax": true, | ||
400 | + "showAvg": true, | ||
401 | + "showTotal": true | ||
402 | + }, | ||
403 | + "actions": {} | ||
404 | + }, | ||
405 | + "id": "f928afc4-30d1-8d0c-e3cf-777f9f9d1155" | ||
406 | + }, | ||
407 | + "2a95b473-042d-59d0-2da2-40d0cccb6c8a": { | ||
408 | + "isSystemType": true, | ||
409 | + "bundleAlias": "cards", | ||
410 | + "typeAlias": "timeseries_table", | ||
411 | + "type": "timeseries", | ||
412 | + "title": "New widget", | ||
413 | + "sizeX": 7, | ||
414 | + "sizeY": 7, | ||
415 | + "config": { | ||
416 | + "datasources": [ | ||
417 | + { | ||
418 | + "type": "entity", | ||
419 | + "dataKeys": [ | ||
420 | + { | ||
421 | + "name": "eventsSent", | ||
422 | + "type": "timeseries", | ||
423 | + "label": "Events", | ||
424 | + "color": "#2196f3", | ||
425 | + "settings": { | ||
426 | + "useCellStyleFunction": false, | ||
427 | + "useCellContentFunction": false | ||
428 | + }, | ||
429 | + "_hash": 0.8156044798125357 | ||
430 | + }, | ||
431 | + { | ||
432 | + "name": "eventsProduced", | ||
433 | + "type": "timeseries", | ||
434 | + "label": "Produced", | ||
435 | + "color": "#4caf50", | ||
436 | + "settings": { | ||
437 | + "useCellStyleFunction": false, | ||
438 | + "useCellContentFunction": false | ||
439 | + }, | ||
440 | + "_hash": 0.6538259344015449 | ||
441 | + } | ||
442 | + ], | ||
443 | + "entityAliasId": "b2487e75-2fa4-f211-142c-434dfd50c70c" | ||
444 | + } | ||
445 | + ], | ||
446 | + "timewindow": { | ||
447 | + "realtime": { | ||
448 | + "interval": 1000, | ||
449 | + "timewindowMs": 604800000 | ||
450 | + }, | ||
451 | + "aggregation": { | ||
452 | + "type": "NONE", | ||
453 | + "limit": 200 | ||
454 | + } | ||
455 | + }, | ||
456 | + "showTitle": true, | ||
457 | + "backgroundColor": "rgb(255, 255, 255)", | ||
458 | + "color": "rgba(0, 0, 0, 0.87)", | ||
459 | + "padding": "8px", | ||
460 | + "settings": { | ||
461 | + "showTimestamp": true, | ||
462 | + "displayPagination": true, | ||
463 | + "defaultPageSize": 6, | ||
464 | + "hideEmptyLines": true | ||
465 | + }, | ||
466 | + "title": "Total Messages", | ||
467 | + "dropShadow": true, | ||
468 | + "enableFullscreen": true, | ||
469 | + "titleStyle": { | ||
470 | + "fontSize": "16px", | ||
471 | + "fontWeight": 400 | ||
472 | + }, | ||
473 | + "useDashboardTimewindow": false, | ||
474 | + "showLegend": false, | ||
475 | + "widgetStyle": {}, | ||
476 | + "actions": {}, | ||
477 | + "showTitleIcon": false, | ||
478 | + "titleIcon": null, | ||
479 | + "iconColor": "rgba(0, 0, 0, 0.87)", | ||
480 | + "iconSize": "24px", | ||
481 | + "titleTooltip": "", | ||
482 | + "displayTimewindow": true, | ||
483 | + "legendConfig": { | ||
484 | + "direction": "column", | ||
485 | + "position": "bottom", | ||
486 | + "showMin": false, | ||
487 | + "showMax": false, | ||
488 | + "showAvg": true, | ||
489 | + "showTotal": false | ||
490 | + } | ||
491 | + }, | ||
492 | + "id": "2a95b473-042d-59d0-2da2-40d0cccb6c8a" | ||
493 | + }, | ||
494 | + "aaa69366-aacc-9028-65aa-645c0f8533ec": { | ||
495 | + "isSystemType": true, | ||
496 | + "bundleAlias": "charts", | ||
497 | + "typeAlias": "basic_timeseries", | ||
498 | + "type": "timeseries", | ||
499 | + "title": "New widget", | ||
500 | + "sizeX": 17, | ||
501 | + "sizeY": 4, | ||
502 | + "config": { | ||
503 | + "datasources": [ | ||
504 | + { | ||
505 | + "type": "entity", | ||
506 | + "dataKeys": [ | ||
507 | + { | ||
508 | + "name": "eventsSent", | ||
509 | + "type": "timeseries", | ||
510 | + "label": "eventsSent", | ||
511 | + "color": "#2196f3", | ||
512 | + "settings": { | ||
513 | + "excludeFromStacking": false, | ||
514 | + "hideDataByDefault": false, | ||
515 | + "disableDataHiding": false, | ||
516 | + "removeFromLegend": false, | ||
517 | + "showLines": true, | ||
518 | + "fillLines": false, | ||
519 | + "showPoints": false, | ||
520 | + "showPointShape": "circle", | ||
521 | + "pointShapeFormatter": "var size = radius * Math.sqrt(Math.PI) / 2;\nctx.moveTo(x - size, y - size);\nctx.lineTo(x + size, y + size);\nctx.moveTo(x - size, y + size);\nctx.lineTo(x + size, y - size);", | ||
522 | + "showPointsLineWidth": 5, | ||
523 | + "showPointsRadius": 3, | ||
524 | + "tooltipValueFormatter": "", | ||
525 | + "showSeparateAxis": false, | ||
526 | + "axisTitle": "", | ||
527 | + "axisPosition": "left", | ||
528 | + "axisTicksFormatter": "", | ||
529 | + "comparisonSettings": { | ||
530 | + "showValuesForComparison": true, | ||
531 | + "comparisonValuesLabel": "", | ||
532 | + "color": "" | ||
533 | + } | ||
534 | + }, | ||
535 | + "_hash": 0.41414001784591314 | ||
536 | + }, | ||
537 | + { | ||
538 | + "name": "eventsProduced", | ||
539 | + "type": "timeseries", | ||
540 | + "label": "eventsProduced", | ||
541 | + "color": "#4caf50", | ||
542 | + "settings": { | ||
543 | + "excludeFromStacking": false, | ||
544 | + "hideDataByDefault": false, | ||
545 | + "disableDataHiding": false, | ||
546 | + "removeFromLegend": false, | ||
547 | + "showLines": true, | ||
548 | + "fillLines": false, | ||
549 | + "showPoints": false, | ||
550 | + "showPointShape": "circle", | ||
551 | + "pointShapeFormatter": "var size = radius * Math.sqrt(Math.PI) / 2;\nctx.moveTo(x - size, y - size);\nctx.lineTo(x + size, y + size);\nctx.moveTo(x - size, y + size);\nctx.lineTo(x + size, y - size);", | ||
552 | + "showPointsLineWidth": 5, | ||
553 | + "showPointsRadius": 3, | ||
554 | + "tooltipValueFormatter": "", | ||
555 | + "showSeparateAxis": false, | ||
556 | + "axisTitle": "", | ||
557 | + "axisPosition": "left", | ||
558 | + "axisTicksFormatter": "", | ||
559 | + "comparisonSettings": { | ||
560 | + "showValuesForComparison": true, | ||
561 | + "comparisonValuesLabel": "", | ||
562 | + "color": "" | ||
563 | + } | ||
564 | + }, | ||
565 | + "_hash": 0.7819101846284422 | ||
566 | + } | ||
567 | + ], | ||
568 | + "entityAliasId": "b2487e75-2fa4-f211-142c-434dfd50c70c" | ||
569 | + } | ||
570 | + ], | ||
571 | + "timewindow": { | ||
572 | + "realtime": { | ||
573 | + "timewindowMs": 60000 | ||
574 | + } | ||
575 | + }, | ||
576 | + "showTitle": true, | ||
577 | + "backgroundColor": "#fff", | ||
578 | + "color": "rgba(0, 0, 0, 0.87)", | ||
579 | + "padding": "8px", | ||
580 | + "settings": { | ||
581 | + "shadowSize": 4, | ||
582 | + "fontColor": "#545454", | ||
583 | + "fontSize": 10, | ||
584 | + "xaxis": { | ||
585 | + "showLabels": true, | ||
586 | + "color": "#545454" | ||
587 | + }, | ||
588 | + "yaxis": { | ||
589 | + "showLabels": true, | ||
590 | + "color": "#545454" | ||
591 | + }, | ||
592 | + "grid": { | ||
593 | + "color": "#545454", | ||
594 | + "tickColor": "#DDDDDD", | ||
595 | + "verticalLines": true, | ||
596 | + "horizontalLines": true, | ||
597 | + "outlineWidth": 1 | ||
598 | + }, | ||
599 | + "stack": false, | ||
600 | + "tooltipIndividual": false, | ||
601 | + "timeForComparison": "months", | ||
602 | + "xaxisSecond": { | ||
603 | + "axisPosition": "top", | ||
604 | + "showLabels": true | ||
605 | + } | ||
606 | + }, | ||
607 | + "title": "History information", | ||
608 | + "dropShadow": true, | ||
609 | + "enableFullscreen": true, | ||
610 | + "titleStyle": { | ||
611 | + "fontSize": "16px", | ||
612 | + "fontWeight": 400 | ||
613 | + }, | ||
614 | + "mobileHeight": null, | ||
615 | + "showTitleIcon": false, | ||
616 | + "titleIcon": null, | ||
617 | + "iconColor": "rgba(0, 0, 0, 0.87)", | ||
618 | + "iconSize": "24px", | ||
619 | + "titleTooltip": "", | ||
620 | + "widgetStyle": {}, | ||
621 | + "useDashboardTimewindow": true, | ||
622 | + "displayTimewindow": true, | ||
623 | + "showLegend": true, | ||
624 | + "legendConfig": { | ||
625 | + "direction": "column", | ||
626 | + "position": "right", | ||
627 | + "showMin": true, | ||
628 | + "showMax": true, | ||
629 | + "showAvg": true, | ||
630 | + "showTotal": true | ||
631 | + }, | ||
632 | + "actions": {} | ||
633 | + }, | ||
634 | + "id": "aaa69366-aacc-9028-65aa-645c0f8533ec" | ||
635 | + }, | ||
636 | + "ce5c7d01-a3ef-5cf0-4578-8505135c23a0": { | ||
637 | + "isSystemType": true, | ||
638 | + "bundleAlias": "charts", | ||
639 | + "typeAlias": "basic_timeseries", | ||
640 | + "type": "timeseries", | ||
641 | + "title": "New widget", | ||
642 | + "sizeX": 17, | ||
643 | + "sizeY": 4, | ||
644 | + "config": { | ||
645 | + "datasources": [ | ||
646 | + { | ||
647 | + "type": "entity", | ||
648 | + "dataKeys": [ | ||
649 | + { | ||
650 | + "name": "bleEventsProduced", | ||
651 | + "type": "timeseries", | ||
652 | + "label": "bleEventsProduced", | ||
653 | + "color": "#2196f3", | ||
654 | + "settings": { | ||
655 | + "excludeFromStacking": false, | ||
656 | + "hideDataByDefault": false, | ||
657 | + "disableDataHiding": false, | ||
658 | + "removeFromLegend": false, | ||
659 | + "showLines": true, | ||
660 | + "fillLines": false, | ||
661 | + "showPoints": false, | ||
662 | + "showPointShape": "circle", | ||
663 | + "pointShapeFormatter": "var size = radius * Math.sqrt(Math.PI) / 2;\nctx.moveTo(x - size, y - size);\nctx.lineTo(x + size, y + size);\nctx.moveTo(x - size, y + size);\nctx.lineTo(x + size, y - size);", | ||
664 | + "showPointsLineWidth": 5, | ||
665 | + "showPointsRadius": 3, | ||
666 | + "tooltipValueFormatter": "", | ||
667 | + "showSeparateAxis": false, | ||
668 | + "axisTitle": "", | ||
669 | + "axisPosition": "left", | ||
670 | + "axisTicksFormatter": "", | ||
671 | + "comparisonSettings": { | ||
672 | + "showValuesForComparison": true, | ||
673 | + "comparisonValuesLabel": "", | ||
674 | + "color": "" | ||
675 | + } | ||
676 | + }, | ||
677 | + "_hash": 0.5625165504526104 | ||
678 | + }, | ||
679 | + { | ||
680 | + "name": "bleEventsSent", | ||
681 | + "type": "timeseries", | ||
682 | + "label": "bleEventsSent", | ||
683 | + "color": "#4caf50", | ||
684 | + "settings": { | ||
685 | + "excludeFromStacking": false, | ||
686 | + "hideDataByDefault": false, | ||
687 | + "disableDataHiding": false, | ||
688 | + "removeFromLegend": false, | ||
689 | + "showLines": true, | ||
690 | + "fillLines": false, | ||
691 | + "showPoints": false, | ||
692 | + "showPointShape": "circle", | ||
693 | + "pointShapeFormatter": "var size = radius * Math.sqrt(Math.PI) / 2;\nctx.moveTo(x - size, y - size);\nctx.lineTo(x + size, y + size);\nctx.moveTo(x - size, y + size);\nctx.lineTo(x + size, y - size);", | ||
694 | + "showPointsLineWidth": 5, | ||
695 | + "showPointsRadius": 3, | ||
696 | + "tooltipValueFormatter": "", | ||
697 | + "showSeparateAxis": false, | ||
698 | + "axisTitle": "", | ||
699 | + "axisPosition": "left", | ||
700 | + "axisTicksFormatter": "", | ||
701 | + "comparisonSettings": { | ||
702 | + "showValuesForComparison": true, | ||
703 | + "comparisonValuesLabel": "", | ||
704 | + "color": "" | ||
705 | + } | ||
706 | + }, | ||
707 | + "_hash": 0.6817950080745288 | ||
708 | + } | ||
709 | + ], | ||
710 | + "entityAliasId": "b2487e75-2fa4-f211-142c-434dfd50c70c" | ||
711 | + } | ||
712 | + ], | ||
713 | + "timewindow": { | ||
714 | + "realtime": { | ||
715 | + "interval": 5000, | ||
716 | + "timewindowMs": 120000 | ||
717 | + }, | ||
718 | + "aggregation": { | ||
719 | + "type": "AVG", | ||
720 | + "limit": 25000 | ||
721 | + } | ||
722 | + }, | ||
723 | + "showTitle": true, | ||
724 | + "backgroundColor": "#fff", | ||
725 | + "color": "rgba(0, 0, 0, 0.87)", | ||
726 | + "padding": "8px", | ||
727 | + "settings": { | ||
728 | + "shadowSize": 4, | ||
729 | + "fontColor": "#545454", | ||
730 | + "fontSize": 10, | ||
731 | + "xaxis": { | ||
732 | + "showLabels": true, | ||
733 | + "color": "#545454" | ||
734 | + }, | ||
735 | + "yaxis": { | ||
736 | + "showLabels": true, | ||
737 | + "color": "#545454" | ||
738 | + }, | ||
739 | + "grid": { | ||
740 | + "color": "#545454", | ||
741 | + "tickColor": "#DDDDDD", | ||
742 | + "verticalLines": true, | ||
743 | + "horizontalLines": true, | ||
744 | + "outlineWidth": 1 | ||
745 | + }, | ||
746 | + "stack": false, | ||
747 | + "tooltipIndividual": false, | ||
748 | + "timeForComparison": "months", | ||
749 | + "xaxisSecond": { | ||
750 | + "axisPosition": "top", | ||
751 | + "showLabels": true | ||
752 | + } | ||
753 | + }, | ||
754 | + "title": "Real time information", | ||
755 | + "dropShadow": true, | ||
756 | + "enableFullscreen": true, | ||
757 | + "titleStyle": { | ||
758 | + "fontSize": "16px", | ||
759 | + "fontWeight": 400 | ||
760 | + }, | ||
761 | + "mobileHeight": null, | ||
762 | + "showTitleIcon": false, | ||
763 | + "titleIcon": null, | ||
764 | + "iconColor": "rgba(0, 0, 0, 0.87)", | ||
765 | + "iconSize": "24px", | ||
766 | + "titleTooltip": "", | ||
767 | + "widgetStyle": {}, | ||
768 | + "useDashboardTimewindow": false, | ||
769 | + "displayTimewindow": true, | ||
770 | + "showLegend": true, | ||
771 | + "legendConfig": { | ||
772 | + "direction": "column", | ||
773 | + "position": "right", | ||
774 | + "showMin": true, | ||
775 | + "showMax": true, | ||
776 | + "showAvg": true, | ||
777 | + "showTotal": true | ||
778 | + }, | ||
779 | + "actions": {} | ||
780 | + }, | ||
781 | + "id": "ce5c7d01-a3ef-5cf0-4578-8505135c23a0" | ||
782 | + }, | ||
783 | + "466f046d-6005-a168-b107-60fcb2469cd5": { | ||
784 | + "isSystemType": true, | ||
785 | + "bundleAlias": "gateway_widgets", | ||
786 | + "typeAlias": "attributes_card", | ||
787 | + "type": "latest", | ||
788 | + "title": "New widget", | ||
789 | + "sizeX": 7, | ||
790 | + "sizeY": 5, | ||
791 | + "config": { | ||
792 | + "datasources": [ | ||
793 | + { | ||
794 | + "type": "entity", | ||
795 | + "dataKeys": [], | ||
796 | + "entityAliasId": "b2487e75-2fa4-f211-142c-434dfd50c70c" | ||
797 | + } | ||
798 | + ], | ||
799 | + "timewindow": { | ||
800 | + "realtime": { | ||
801 | + "timewindowMs": 60000 | ||
802 | + } | ||
803 | + }, | ||
804 | + "showTitle": true, | ||
805 | + "backgroundColor": "#fff", | ||
806 | + "color": "rgba(0, 0, 0, 0.87)", | ||
807 | + "padding": "8px", | ||
808 | + "settings": { | ||
809 | + "eventsTitle": "Gateway Events Form", | ||
810 | + "eventsReg": [ | ||
811 | + "EventsProduced", | ||
812 | + "EventsSent" | ||
813 | + ] | ||
814 | + }, | ||
815 | + "title": "Gateway events", | ||
816 | + "showTitleIcon": false, | ||
817 | + "titleIcon": null, | ||
818 | + "iconColor": "rgba(0, 0, 0, 0.87)", | ||
819 | + "iconSize": "24px", | ||
820 | + "titleTooltip": "", | ||
821 | + "dropShadow": true, | ||
822 | + "enableFullscreen": true, | ||
823 | + "widgetStyle": {}, | ||
824 | + "titleStyle": { | ||
825 | + "fontSize": "16px", | ||
826 | + "fontWeight": 400 | ||
827 | + }, | ||
828 | + "useDashboardTimewindow": true, | ||
829 | + "displayTimewindow": true, | ||
830 | + "showLegend": false, | ||
831 | + "actions": {} | ||
832 | + }, | ||
833 | + "id": "466f046d-6005-a168-b107-60fcb2469cd5" | ||
834 | + }, | ||
835 | + "8fc32225-164f-3258-73f7-e6b6d959cf0b": { | ||
836 | + "isSystemType": true, | ||
837 | + "bundleAlias": "gateway_widgets", | ||
838 | + "typeAlias": "config_form_latest", | ||
839 | + "type": "latest", | ||
840 | + "title": "New widget", | ||
841 | + "sizeX": 10, | ||
842 | + "sizeY": 9, | ||
843 | + "config": { | ||
844 | + "datasources": [ | ||
845 | + { | ||
846 | + "type": "entity", | ||
847 | + "dataKeys": [], | ||
848 | + "entityAliasId": "b2487e75-2fa4-f211-142c-434dfd50c70c" | ||
849 | + } | ||
850 | + ], | ||
851 | + "timewindow": { | ||
852 | + "realtime": { | ||
853 | + "timewindowMs": 60000 | ||
854 | + } | ||
855 | + }, | ||
856 | + "showTitle": true, | ||
857 | + "backgroundColor": "#fff", | ||
858 | + "color": "rgba(0, 0, 0, 0.87)", | ||
859 | + "padding": "8px", | ||
860 | + "settings": { | ||
861 | + "gatewayTitle": "Gateway configuration (Single device)", | ||
862 | + "readOnly": false | ||
863 | + }, | ||
864 | + "title": "New Gateway configuration (Single device)", | ||
865 | + "showTitleIcon": false, | ||
866 | + "titleIcon": null, | ||
867 | + "iconColor": "rgba(0, 0, 0, 0.87)", | ||
868 | + "iconSize": "24px", | ||
869 | + "titleTooltip": "", | ||
870 | + "dropShadow": true, | ||
871 | + "enableFullscreen": true, | ||
872 | + "widgetStyle": {}, | ||
873 | + "titleStyle": { | ||
874 | + "fontSize": "16px", | ||
875 | + "fontWeight": 400 | ||
876 | + }, | ||
877 | + "useDashboardTimewindow": true, | ||
878 | + "displayTimewindow": true, | ||
879 | + "showLegend": false, | ||
880 | + "actions": {} | ||
881 | + }, | ||
882 | + "id": "8fc32225-164f-3258-73f7-e6b6d959cf0b" | ||
883 | + }, | ||
884 | + "063fc179-c9fd-f952-e714-f24e9c43c05c": { | ||
885 | + "isSystemType": true, | ||
886 | + "bundleAlias": "control_widgets", | ||
887 | + "typeAlias": "rpcbutton", | ||
888 | + "type": "rpc", | ||
889 | + "title": "New widget", | ||
890 | + "sizeX": 4, | ||
891 | + "sizeY": 2, | ||
892 | + "config": { | ||
893 | + "targetDeviceAliases": [], | ||
894 | + "showTitle": false, | ||
895 | + "backgroundColor": "#e6e7e8", | ||
896 | + "color": "rgba(0, 0, 0, 0.87)", | ||
897 | + "padding": "0px", | ||
898 | + "settings": { | ||
899 | + "requestTimeout": 5000, | ||
900 | + "oneWayElseTwoWay": true, | ||
901 | + "styleButton": { | ||
902 | + "isRaised": true, | ||
903 | + "isPrimary": false | ||
904 | + }, | ||
905 | + "methodParams": "{}", | ||
906 | + "methodName": "gateway_reboot", | ||
907 | + "buttonText": "GATEWAY REBOOT" | ||
908 | + }, | ||
909 | + "title": "New RPC Button", | ||
910 | + "dropShadow": true, | ||
911 | + "enableFullscreen": false, | ||
912 | + "widgetStyle": {}, | ||
913 | + "titleStyle": { | ||
914 | + "fontSize": "16px", | ||
915 | + "fontWeight": 400 | ||
916 | + }, | ||
917 | + "useDashboardTimewindow": true, | ||
918 | + "showLegend": false, | ||
919 | + "actions": {}, | ||
920 | + "datasources": [], | ||
921 | + "showTitleIcon": false, | ||
922 | + "titleIcon": null, | ||
923 | + "iconColor": "rgba(0, 0, 0, 0.87)", | ||
924 | + "iconSize": "24px", | ||
925 | + "titleTooltip": "", | ||
926 | + "displayTimewindow": true, | ||
927 | + "targetDeviceAliasIds": [ | ||
928 | + "b2487e75-2fa4-f211-142c-434dfd50c70c" | ||
929 | + ] | ||
930 | + }, | ||
931 | + "id": "063fc179-c9fd-f952-e714-f24e9c43c05c" | ||
932 | + }, | ||
933 | + "3c2134cc-27a0-93e1-dbe1-2fa7c1ce16b7": { | ||
934 | + "isSystemType": true, | ||
935 | + "bundleAlias": "control_widgets", | ||
936 | + "typeAlias": "rpcbutton", | ||
937 | + "type": "rpc", | ||
938 | + "title": "New widget", | ||
939 | + "sizeX": 4, | ||
940 | + "sizeY": 2, | ||
941 | + "config": { | ||
942 | + "targetDeviceAliases": [], | ||
943 | + "showTitle": false, | ||
944 | + "backgroundColor": "#e6e7e8", | ||
945 | + "color": "rgba(0, 0, 0, 0.87)", | ||
946 | + "padding": "0px", | ||
947 | + "settings": { | ||
948 | + "requestTimeout": 5000, | ||
949 | + "oneWayElseTwoWay": true, | ||
950 | + "styleButton": { | ||
951 | + "isRaised": true, | ||
952 | + "isPrimary": false | ||
953 | + }, | ||
954 | + "methodName": "gateway_restart", | ||
955 | + "methodParams": "{}", | ||
956 | + "buttonText": "gateway restart" | ||
957 | + }, | ||
958 | + "title": "New RPC Button", | ||
959 | + "dropShadow": true, | ||
960 | + "enableFullscreen": false, | ||
961 | + "widgetStyle": {}, | ||
962 | + "titleStyle": { | ||
963 | + "fontSize": "16px", | ||
964 | + "fontWeight": 400 | ||
965 | + }, | ||
966 | + "useDashboardTimewindow": true, | ||
967 | + "showLegend": false, | ||
968 | + "actions": {}, | ||
969 | + "datasources": [], | ||
970 | + "showTitleIcon": false, | ||
971 | + "titleIcon": null, | ||
972 | + "iconColor": "rgba(0, 0, 0, 0.87)", | ||
973 | + "iconSize": "24px", | ||
974 | + "titleTooltip": "", | ||
975 | + "displayTimewindow": true, | ||
976 | + "targetDeviceAliasIds": [ | ||
977 | + "b2487e75-2fa4-f211-142c-434dfd50c70c" | ||
978 | + ] | ||
979 | + }, | ||
980 | + "id": "3c2134cc-27a0-93e1-dbe1-2fa7c1ce16b7" | ||
981 | + }, | ||
982 | + "6770b6ba-eff8-df05-75f8-c1f9326d4842": { | ||
983 | + "isSystemType": true, | ||
984 | + "bundleAlias": "input_widgets", | ||
985 | + "typeAlias": "markers_placement_openstreetmap", | ||
986 | + "type": "latest", | ||
987 | + "title": "New widget", | ||
988 | + "sizeX": 6, | ||
989 | + "sizeY": 4, | ||
990 | + "config": { | ||
991 | + "datasources": [ | ||
992 | + { | ||
993 | + "type": "entity", | ||
994 | + "dataKeys": [ | ||
995 | + { | ||
996 | + "name": "latitude", | ||
997 | + "type": "attribute", | ||
998 | + "label": "latitude", | ||
999 | + "color": "#2196f3", | ||
1000 | + "settings": {}, | ||
1001 | + "_hash": 0.9743324774725604 | ||
1002 | + }, | ||
1003 | + { | ||
1004 | + "name": "longitude", | ||
1005 | + "type": "attribute", | ||
1006 | + "label": "longitude", | ||
1007 | + "color": "#4caf50", | ||
1008 | + "settings": {}, | ||
1009 | + "_hash": 0.5530093635101525 | ||
1010 | + } | ||
1011 | + ], | ||
1012 | + "entityAliasId": "b2487e75-2fa4-f211-142c-434dfd50c70c" | ||
1013 | + } | ||
1014 | + ], | ||
1015 | + "timewindow": { | ||
1016 | + "realtime": { | ||
1017 | + "timewindowMs": 60000 | ||
1018 | + } | ||
1019 | + }, | ||
1020 | + "showTitle": false, | ||
1021 | + "backgroundColor": "#fff", | ||
1022 | + "color": "rgba(0, 0, 0, 0.87)", | ||
1023 | + "padding": "8px", | ||
1024 | + "settings": { | ||
1025 | + "fitMapBounds": true, | ||
1026 | + "latKeyName": "latitude", | ||
1027 | + "lngKeyName": "longitude", | ||
1028 | + "showLabel": true, | ||
1029 | + "label": "${entityName}", | ||
1030 | + "tooltipPattern": "<b>${entityName}</b><br/><br/><b>Latitude:</b> ${latitude:7}<br/><b>Longitude:</b> ${longitude:7}<br/><br/><link-act name='delete'>Delete</link-act>", | ||
1031 | + "markerImageSize": 34, | ||
1032 | + "useColorFunction": false, | ||
1033 | + "markerImages": [], | ||
1034 | + "useMarkerImageFunction": false, | ||
1035 | + "color": "#fe7569", | ||
1036 | + "mapProvider": "OpenStreetMap.Mapnik", | ||
1037 | + "showTooltip": true, | ||
1038 | + "autocloseTooltip": true, | ||
1039 | + "defaultCenterPosition": [ | ||
1040 | + 0, | ||
1041 | + 0 | ||
1042 | + ], | ||
1043 | + "customProviderTileUrl": "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", | ||
1044 | + "showTooltipAction": "click", | ||
1045 | + "polygonKeyName": "coordinates", | ||
1046 | + "polygonOpacity": 0.5, | ||
1047 | + "polygonStrokeOpacity": 1, | ||
1048 | + "polygonStrokeWeight": 1, | ||
1049 | + "zoomOnClick": true, | ||
1050 | + "showCoverageOnHover": true, | ||
1051 | + "animate": true, | ||
1052 | + "maxClusterRadius": 80, | ||
1053 | + "removeOutsideVisibleBounds": true, | ||
1054 | + "defaultZoomLevel": 5 | ||
1055 | + }, | ||
1056 | + "title": "Gateway Location", | ||
1057 | + "dropShadow": true, | ||
1058 | + "enableFullscreen": false, | ||
1059 | + "titleStyle": { | ||
1060 | + "fontSize": "16px", | ||
1061 | + "fontWeight": 400 | ||
1062 | + }, | ||
1063 | + "useDashboardTimewindow": true, | ||
1064 | + "showLegend": false, | ||
1065 | + "widgetStyle": {}, | ||
1066 | + "actions": { | ||
1067 | + "tooltipAction": [ | ||
1068 | + { | ||
1069 | + "id": "54c293c4-9ca6-e34f-dc6a-0271944c1c66", | ||
1070 | + "name": "delete", | ||
1071 | + "icon": "more_horiz", | ||
1072 | + "type": "custom", | ||
1073 | + "customFunction": "var $rootScope = widgetContext.$scope.$injector.get('$rootScope');\nvar entityDatasource = widgetContext.map.subscription.datasources.filter(\n function(entity) {\n return entity.entityId === entityId.id\n });\n\nwidgetContext.map.saveMarkerLocation(entityDatasource[0],\n widgetContext.map.locations[0], {\n \"lat\": null,\n \"lng\": null\n }).then(function succes() {\n $rootScope.$broadcast('widgetForceReInit');\n });" | ||
1074 | + } | ||
1075 | + ] | ||
1076 | + }, | ||
1077 | + "showTitleIcon": false, | ||
1078 | + "titleIcon": null, | ||
1079 | + "iconColor": "rgba(0, 0, 0, 0.87)", | ||
1080 | + "iconSize": "24px", | ||
1081 | + "titleTooltip": "", | ||
1082 | + "displayTimewindow": true | ||
1083 | + }, | ||
1084 | + "id": "6770b6ba-eff8-df05-75f8-c1f9326d4842" | ||
1085 | + } | ||
1086 | + }, | ||
1087 | + "states": { | ||
1088 | + "main_gateway": { | ||
1089 | + "name": "Gateways", | ||
1090 | + "root": true, | ||
1091 | + "layouts": { | ||
1092 | + "main": { | ||
1093 | + "widgets": { | ||
1094 | + "94715984-ae74-76e4-20b7-2f956b01ed80": { | ||
1095 | + "sizeX": 24, | ||
1096 | + "sizeY": 12, | ||
1097 | + "row": 0, | ||
1098 | + "col": 0 | ||
1099 | + } | ||
1100 | + }, | ||
1101 | + "gridSettings": { | ||
1102 | + "backgroundColor": "#eeeeee", | ||
1103 | + "color": "rgba(0,0,0,0.870588)", | ||
1104 | + "columns": 24, | ||
1105 | + "margins": [ | ||
1106 | + 10, | ||
1107 | + 10 | ||
1108 | + ], | ||
1109 | + "backgroundSizeMode": "100%", | ||
1110 | + "autoFillHeight": true, | ||
1111 | + "mobileAutoFillHeight": false, | ||
1112 | + "mobileRowHeight": 70 | ||
1113 | + } | ||
1114 | + } | ||
1115 | + } | ||
1116 | + }, | ||
1117 | + "__entityname__config": { | ||
1118 | + "name": "${entityName} Configuration", | ||
1119 | + "root": false, | ||
1120 | + "layouts": { | ||
1121 | + "main": { | ||
1122 | + "widgets": { | ||
1123 | + "eadabbc7-519e-76fc-ba10-b3fe8c18da10": { | ||
1124 | + "sizeX": 14, | ||
1125 | + "sizeY": 13, | ||
1126 | + "row": 0, | ||
1127 | + "col": 10 | ||
1128 | + }, | ||
1129 | + "8fc32225-164f-3258-73f7-e6b6d959cf0b": { | ||
1130 | + "sizeX": 10, | ||
1131 | + "sizeY": 9, | ||
1132 | + "row": 0, | ||
1133 | + "col": 0 | ||
1134 | + }, | ||
1135 | + "063fc179-c9fd-f952-e714-f24e9c43c05c": { | ||
1136 | + "sizeX": 4, | ||
1137 | + "sizeY": 2, | ||
1138 | + "row": 9, | ||
1139 | + "col": 0 | ||
1140 | + }, | ||
1141 | + "3c2134cc-27a0-93e1-dbe1-2fa7c1ce16b7": { | ||
1142 | + "sizeX": 4, | ||
1143 | + "sizeY": 2, | ||
1144 | + "row": 11, | ||
1145 | + "col": 0 | ||
1146 | + }, | ||
1147 | + "6770b6ba-eff8-df05-75f8-c1f9326d4842": { | ||
1148 | + "sizeX": 6, | ||
1149 | + "sizeY": 4, | ||
1150 | + "row": 9, | ||
1151 | + "col": 4 | ||
1152 | + } | ||
1153 | + }, | ||
1154 | + "gridSettings": { | ||
1155 | + "backgroundColor": "#eeeeee", | ||
1156 | + "color": "rgba(0,0,0,0.870588)", | ||
1157 | + "columns": 24, | ||
1158 | + "margins": [ | ||
1159 | + 10, | ||
1160 | + 10 | ||
1161 | + ], | ||
1162 | + "backgroundSizeMode": "100%", | ||
1163 | + "autoFillHeight": true, | ||
1164 | + "mobileAutoFillHeight": false, | ||
1165 | + "mobileRowHeight": 70 | ||
1166 | + } | ||
1167 | + } | ||
1168 | + } | ||
1169 | + }, | ||
1170 | + "__entityname_grafic": { | ||
1171 | + "name": "${entityName} Details", | ||
1172 | + "root": false, | ||
1173 | + "layouts": { | ||
1174 | + "main": { | ||
1175 | + "widgets": { | ||
1176 | + "f928afc4-30d1-8d0c-e3cf-777f9f9d1155": { | ||
1177 | + "sizeX": 17, | ||
1178 | + "sizeY": 4, | ||
1179 | + "mobileHeight": null, | ||
1180 | + "row": 4, | ||
1181 | + "col": 7 | ||
1182 | + }, | ||
1183 | + "2a95b473-042d-59d0-2da2-40d0cccb6c8a": { | ||
1184 | + "sizeX": 7, | ||
1185 | + "sizeY": 7, | ||
1186 | + "row": 5, | ||
1187 | + "col": 0 | ||
1188 | + }, | ||
1189 | + "aaa69366-aacc-9028-65aa-645c0f8533ec": { | ||
1190 | + "sizeX": 17, | ||
1191 | + "sizeY": 4, | ||
1192 | + "mobileHeight": null, | ||
1193 | + "row": 0, | ||
1194 | + "col": 7 | ||
1195 | + }, | ||
1196 | + "ce5c7d01-a3ef-5cf0-4578-8505135c23a0": { | ||
1197 | + "sizeX": 17, | ||
1198 | + "sizeY": 4, | ||
1199 | + "mobileHeight": null, | ||
1200 | + "row": 8, | ||
1201 | + "col": 7 | ||
1202 | + }, | ||
1203 | + "466f046d-6005-a168-b107-60fcb2469cd5": { | ||
1204 | + "sizeX": 7, | ||
1205 | + "sizeY": 5, | ||
1206 | + "row": 0, | ||
1207 | + "col": 0 | ||
1208 | + } | ||
1209 | + }, | ||
1210 | + "gridSettings": { | ||
1211 | + "backgroundColor": "#eeeeee", | ||
1212 | + "color": "rgba(0,0,0,0.870588)", | ||
1213 | + "columns": 24, | ||
1214 | + "margins": [ | ||
1215 | + 10, | ||
1216 | + 10 | ||
1217 | + ], | ||
1218 | + "backgroundSizeMode": "auto 100%", | ||
1219 | + "autoFillHeight": true, | ||
1220 | + "mobileAutoFillHeight": true, | ||
1221 | + "mobileRowHeight": 70 | ||
1222 | + } | ||
1223 | + } | ||
1224 | + } | ||
1225 | + } | ||
1226 | + }, | ||
1227 | + "entityAliases": { | ||
1228 | + "3e0f533a-0db1-3292-184f-06e73535061a": { | ||
1229 | + "id": "3e0f533a-0db1-3292-184f-06e73535061a", | ||
1230 | + "alias": "Gateways", | ||
1231 | + "filter": { | ||
1232 | + "type": "deviceType", | ||
1233 | + "resolveMultiple": true, | ||
1234 | + "deviceType": "gateway", | ||
1235 | + "deviceNameFilter": "" | ||
1236 | + } | ||
1237 | + }, | ||
1238 | + "b2487e75-2fa4-f211-142c-434dfd50c70c": { | ||
1239 | + "id": "b2487e75-2fa4-f211-142c-434dfd50c70c", | ||
1240 | + "alias": "Current Gateway", | ||
1241 | + "filter": { | ||
1242 | + "type": "stateEntity", | ||
1243 | + "resolveMultiple": false, | ||
1244 | + "stateEntityParamName": "", | ||
1245 | + "defaultStateEntity": null | ||
1246 | + } | ||
1247 | + } | ||
1248 | + }, | ||
1249 | + "timewindow": { | ||
1250 | + "realtime": { | ||
1251 | + "interval": 1000, | ||
1252 | + "timewindowMs": 86400000 | ||
1253 | + }, | ||
1254 | + "aggregation": { | ||
1255 | + "type": "NONE", | ||
1256 | + "limit": 25000 | ||
1257 | + }, | ||
1258 | + "hideInterval": false, | ||
1259 | + "hideAggregation": false, | ||
1260 | + "hideAggInterval": false | ||
1261 | + }, | ||
1262 | + "settings": { | ||
1263 | + "stateControllerId": "entity", | ||
1264 | + "showTitle": true, | ||
1265 | + "showDashboardsSelect": true, | ||
1266 | + "showEntitiesSelect": true, | ||
1267 | + "showDashboardTimewindow": true, | ||
1268 | + "showDashboardExport": true, | ||
1269 | + "toolbarAlwaysOpen": true, | ||
1270 | + "titleColor": "rgba(0,0,0,0.870588)" | ||
1271 | + } | ||
1272 | + }, | ||
1273 | + "name": "Gateways" | ||
1274 | +} |
1 | +{ | ||
2 | + "title": "Rule Engine Statistics", | ||
3 | + "configuration": { | ||
4 | + "widgets": { | ||
5 | + "81987f19-3eac-e4ce-b790-d96e9b54d9a0": { | ||
6 | + "isSystemType": true, | ||
7 | + "bundleAlias": "charts", | ||
8 | + "typeAlias": "basic_timeseries", | ||
9 | + "type": "timeseries", | ||
10 | + "title": "New widget", | ||
11 | + "sizeX": 12, | ||
12 | + "sizeY": 7, | ||
13 | + "config": { | ||
14 | + "datasources": [ | ||
15 | + { | ||
16 | + "type": "entity", | ||
17 | + "dataKeys": [ | ||
18 | + { | ||
19 | + "name": "successfulMsgs", | ||
20 | + "type": "timeseries", | ||
21 | + "label": "${entityName} Successful", | ||
22 | + "color": "#4caf50", | ||
23 | + "settings": { | ||
24 | + "excludeFromStacking": false, | ||
25 | + "hideDataByDefault": false, | ||
26 | + "disableDataHiding": false, | ||
27 | + "removeFromLegend": false, | ||
28 | + "showLines": true, | ||
29 | + "fillLines": false, | ||
30 | + "showPoints": false, | ||
31 | + "showPointShape": "circle", | ||
32 | + "pointShapeFormatter": "var size = radius * Math.sqrt(Math.PI) / 2;\nctx.moveTo(x - size, y - size);\nctx.lineTo(x + size, y + size);\nctx.moveTo(x - size, y + size);\nctx.lineTo(x + size, y - size);", | ||
33 | + "showPointsLineWidth": 5, | ||
34 | + "showPointsRadius": 3, | ||
35 | + "showSeparateAxis": false, | ||
36 | + "axisPosition": "left", | ||
37 | + "thresholds": [ | ||
38 | + { | ||
39 | + "thresholdValueSource": "predefinedValue" | ||
40 | + } | ||
41 | + ], | ||
42 | + "comparisonSettings": { | ||
43 | + "showValuesForComparison": true | ||
44 | + } | ||
45 | + }, | ||
46 | + "_hash": 0.15490750967648736 | ||
47 | + }, | ||
48 | + { | ||
49 | + "name": "failedMsgs", | ||
50 | + "type": "timeseries", | ||
51 | + "label": "${entityName} Permanent Failures", | ||
52 | + "color": "#ef5350", | ||
53 | + "settings": { | ||
54 | + "excludeFromStacking": false, | ||
55 | + "hideDataByDefault": false, | ||
56 | + "disableDataHiding": false, | ||
57 | + "removeFromLegend": false, | ||
58 | + "showLines": true, | ||
59 | + "fillLines": false, | ||
60 | + "showPoints": false, | ||
61 | + "showPointShape": "circle", | ||
62 | + "pointShapeFormatter": "var size = radius * Math.sqrt(Math.PI) / 2;\nctx.moveTo(x - size, y - size);\nctx.lineTo(x + size, y + size);\nctx.moveTo(x - size, y + size);\nctx.lineTo(x + size, y - size);", | ||
63 | + "showPointsLineWidth": 5, | ||
64 | + "showPointsRadius": 3, | ||
65 | + "showSeparateAxis": false, | ||
66 | + "axisPosition": "left", | ||
67 | + "thresholds": [ | ||
68 | + { | ||
69 | + "thresholdValueSource": "predefinedValue" | ||
70 | + } | ||
71 | + ], | ||
72 | + "comparisonSettings": { | ||
73 | + "showValuesForComparison": true | ||
74 | + } | ||
75 | + }, | ||
76 | + "_hash": 0.4186621166514697 | ||
77 | + }, | ||
78 | + { | ||
79 | + "name": "tmpFailed", | ||
80 | + "type": "timeseries", | ||
81 | + "label": "${entityName} Processing Failures", | ||
82 | + "color": "#ffc107", | ||
83 | + "settings": { | ||
84 | + "excludeFromStacking": false, | ||
85 | + "hideDataByDefault": false, | ||
86 | + "disableDataHiding": false, | ||
87 | + "removeFromLegend": false, | ||
88 | + "showLines": true, | ||
89 | + "fillLines": false, | ||
90 | + "showPoints": false, | ||
91 | + "showPointShape": "circle", | ||
92 | + "pointShapeFormatter": "var size = radius * Math.sqrt(Math.PI) / 2;\nctx.moveTo(x - size, y - size);\nctx.lineTo(x + size, y + size);\nctx.moveTo(x - size, y + size);\nctx.lineTo(x + size, y - size);", | ||
93 | + "showPointsLineWidth": 5, | ||
94 | + "showPointsRadius": 3, | ||
95 | + "showSeparateAxis": false, | ||
96 | + "axisPosition": "left", | ||
97 | + "thresholds": [ | ||
98 | + { | ||
99 | + "thresholdValueSource": "predefinedValue" | ||
100 | + } | ||
101 | + ], | ||
102 | + "comparisonSettings": { | ||
103 | + "showValuesForComparison": true | ||
104 | + } | ||
105 | + }, | ||
106 | + "_hash": 0.49891007198715376 | ||
107 | + } | ||
108 | + ], | ||
109 | + "entityAliasId": "140f23dd-e3a0-ed98-6189-03c49d2d8018" | ||
110 | + } | ||
111 | + ], | ||
112 | + "timewindow": { | ||
113 | + "realtime": { | ||
114 | + "interval": 1000, | ||
115 | + "timewindowMs": 300000 | ||
116 | + }, | ||
117 | + "aggregation": { | ||
118 | + "type": "NONE", | ||
119 | + "limit": 8640 | ||
120 | + }, | ||
121 | + "hideInterval": false, | ||
122 | + "hideAggregation": false, | ||
123 | + "hideAggInterval": false | ||
124 | + }, | ||
125 | + "showTitle": true, | ||
126 | + "backgroundColor": "#fff", | ||
127 | + "color": "rgba(0, 0, 0, 0.87)", | ||
128 | + "padding": "8px", | ||
129 | + "settings": { | ||
130 | + "shadowSize": 4, | ||
131 | + "fontColor": "#545454", | ||
132 | + "fontSize": 10, | ||
133 | + "xaxis": { | ||
134 | + "showLabels": true, | ||
135 | + "color": "#545454" | ||
136 | + }, | ||
137 | + "yaxis": { | ||
138 | + "showLabels": true, | ||
139 | + "color": "#545454" | ||
140 | + }, | ||
141 | + "grid": { | ||
142 | + "color": "#545454", | ||
143 | + "tickColor": "#DDDDDD", | ||
144 | + "verticalLines": true, | ||
145 | + "horizontalLines": true, | ||
146 | + "outlineWidth": 1 | ||
147 | + }, | ||
148 | + "stack": false, | ||
149 | + "tooltipIndividual": false, | ||
150 | + "timeForComparison": "months", | ||
151 | + "xaxisSecond": { | ||
152 | + "axisPosition": "top", | ||
153 | + "showLabels": true | ||
154 | + } | ||
155 | + }, | ||
156 | + "title": "Queue Stats", | ||
157 | + "dropShadow": true, | ||
158 | + "enableFullscreen": true, | ||
159 | + "titleStyle": { | ||
160 | + "fontSize": "16px", | ||
161 | + "fontWeight": 400 | ||
162 | + }, | ||
163 | + "mobileHeight": null, | ||
164 | + "showTitleIcon": false, | ||
165 | + "titleIcon": null, | ||
166 | + "iconColor": "rgba(0, 0, 0, 0.87)", | ||
167 | + "iconSize": "24px", | ||
168 | + "titleTooltip": "", | ||
169 | + "widgetStyle": {}, | ||
170 | + "useDashboardTimewindow": false, | ||
171 | + "displayTimewindow": true, | ||
172 | + "showLegend": true, | ||
173 | + "actions": {}, | ||
174 | + "legendConfig": { | ||
175 | + "direction": "column", | ||
176 | + "position": "bottom", | ||
177 | + "showMin": true, | ||
178 | + "showMax": true, | ||
179 | + "showAvg": false, | ||
180 | + "showTotal": true | ||
181 | + } | ||
182 | + }, | ||
183 | + "id": "81987f19-3eac-e4ce-b790-d96e9b54d9a0" | ||
184 | + }, | ||
185 | + "5eb79712-5c24-3060-7e4f-6af36b8f842d": { | ||
186 | + "isSystemType": true, | ||
187 | + "bundleAlias": "cards", | ||
188 | + "typeAlias": "timeseries_table", | ||
189 | + "type": "timeseries", | ||
190 | + "title": "New widget", | ||
191 | + "sizeX": 24, | ||
192 | + "sizeY": 5, | ||
193 | + "config": { | ||
194 | + "datasources": [ | ||
195 | + { | ||
196 | + "type": "entity", | ||
197 | + "dataKeys": [ | ||
198 | + { | ||
199 | + "name": "ruleEngineException", | ||
200 | + "type": "timeseries", | ||
201 | + "label": "Rule Chain", | ||
202 | + "color": "#2196f3", | ||
203 | + "settings": { | ||
204 | + "useCellStyleFunction": false, | ||
205 | + "useCellContentFunction": true, | ||
206 | + "cellContentFunction": "return JSON.parse(value).ruleChainName;" | ||
207 | + }, | ||
208 | + "_hash": 0.9954481282345906 | ||
209 | + }, | ||
210 | + { | ||
211 | + "name": "ruleEngineException", | ||
212 | + "type": "timeseries", | ||
213 | + "label": "Rule Node", | ||
214 | + "color": "#4caf50", | ||
215 | + "settings": { | ||
216 | + "useCellStyleFunction": false, | ||
217 | + "useCellContentFunction": true, | ||
218 | + "cellContentFunction": "return JSON.parse(value).ruleNodeName;" | ||
219 | + }, | ||
220 | + "_hash": 0.18580357036589978 | ||
221 | + }, | ||
222 | + { | ||
223 | + "name": "ruleEngineException", | ||
224 | + "type": "timeseries", | ||
225 | + "label": "Latest Error", | ||
226 | + "color": "#f44336", | ||
227 | + "settings": { | ||
228 | + "useCellStyleFunction": false, | ||
229 | + "useCellContentFunction": true, | ||
230 | + "cellContentFunction": "return JSON.parse(value).message;" | ||
231 | + }, | ||
232 | + "_hash": 0.7255162989552142 | ||
233 | + } | ||
234 | + ], | ||
235 | + "entityAliasId": "140f23dd-e3a0-ed98-6189-03c49d2d8018" | ||
236 | + } | ||
237 | + ], | ||
238 | + "timewindow": { | ||
239 | + "realtime": { | ||
240 | + "interval": 1000, | ||
241 | + "timewindowMs": 86400000 | ||
242 | + }, | ||
243 | + "aggregation": { | ||
244 | + "type": "NONE", | ||
245 | + "limit": 200 | ||
246 | + } | ||
247 | + }, | ||
248 | + "showTitle": true, | ||
249 | + "backgroundColor": "rgb(255, 255, 255)", | ||
250 | + "color": "rgba(0, 0, 0, 0.87)", | ||
251 | + "padding": "8px", | ||
252 | + "settings": { | ||
253 | + "showTimestamp": true, | ||
254 | + "displayPagination": true, | ||
255 | + "defaultPageSize": 10 | ||
256 | + }, | ||
257 | + "title": "Exceptions", | ||
258 | + "dropShadow": true, | ||
259 | + "enableFullscreen": true, | ||
260 | + "titleStyle": { | ||
261 | + "fontSize": "16px", | ||
262 | + "fontWeight": 400 | ||
263 | + }, | ||
264 | + "useDashboardTimewindow": false, | ||
265 | + "showLegend": false, | ||
266 | + "widgetStyle": {}, | ||
267 | + "actions": {}, | ||
268 | + "showTitleIcon": false, | ||
269 | + "titleIcon": null, | ||
270 | + "iconColor": "rgba(0, 0, 0, 0.87)", | ||
271 | + "iconSize": "24px", | ||
272 | + "titleTooltip": "", | ||
273 | + "displayTimewindow": true | ||
274 | + }, | ||
275 | + "id": "5eb79712-5c24-3060-7e4f-6af36b8f842d" | ||
276 | + }, | ||
277 | + "ad3f1417-87a8-750e-fc67-49a2de1466d4": { | ||
278 | + "isSystemType": true, | ||
279 | + "bundleAlias": "charts", | ||
280 | + "typeAlias": "basic_timeseries", | ||
281 | + "type": "timeseries", | ||
282 | + "title": "New widget", | ||
283 | + "sizeX": 12, | ||
284 | + "sizeY": 7, | ||
285 | + "config": { | ||
286 | + "datasources": [ | ||
287 | + { | ||
288 | + "type": "entity", | ||
289 | + "dataKeys": [ | ||
290 | + { | ||
291 | + "name": "timeoutMsgs", | ||
292 | + "type": "timeseries", | ||
293 | + "label": "${entityName} Permanent Timeouts", | ||
294 | + "color": "#4caf50", | ||
295 | + "settings": { | ||
296 | + "excludeFromStacking": false, | ||
297 | + "hideDataByDefault": false, | ||
298 | + "disableDataHiding": false, | ||
299 | + "removeFromLegend": false, | ||
300 | + "showLines": true, | ||
301 | + "fillLines": false, | ||
302 | + "showPoints": false, | ||
303 | + "showPointShape": "circle", | ||
304 | + "pointShapeFormatter": "var size = radius * Math.sqrt(Math.PI) / 2;\nctx.moveTo(x - size, y - size);\nctx.lineTo(x + size, y + size);\nctx.moveTo(x - size, y + size);\nctx.lineTo(x + size, y - size);", | ||
305 | + "showPointsLineWidth": 5, | ||
306 | + "showPointsRadius": 3, | ||
307 | + "showSeparateAxis": false, | ||
308 | + "axisPosition": "left", | ||
309 | + "thresholds": [ | ||
310 | + { | ||
311 | + "thresholdValueSource": "predefinedValue" | ||
312 | + } | ||
313 | + ], | ||
314 | + "comparisonSettings": { | ||
315 | + "showValuesForComparison": true | ||
316 | + } | ||
317 | + }, | ||
318 | + "_hash": 0.565222981550328 | ||
319 | + }, | ||
320 | + { | ||
321 | + "name": "tmpTimeout", | ||
322 | + "type": "timeseries", | ||
323 | + "label": "${entityName} Processing Timeouts", | ||
324 | + "color": "#9c27b0", | ||
325 | + "settings": { | ||
326 | + "excludeFromStacking": false, | ||
327 | + "hideDataByDefault": false, | ||
328 | + "disableDataHiding": false, | ||
329 | + "removeFromLegend": false, | ||
330 | + "showLines": true, | ||
331 | + "fillLines": false, | ||
332 | + "showPoints": false, | ||
333 | + "showPointShape": "circle", | ||
334 | + "pointShapeFormatter": "var size = radius * Math.sqrt(Math.PI) / 2;\nctx.moveTo(x - size, y - size);\nctx.lineTo(x + size, y + size);\nctx.moveTo(x - size, y + size);\nctx.lineTo(x + size, y - size);", | ||
335 | + "showPointsLineWidth": 5, | ||
336 | + "showPointsRadius": 3, | ||
337 | + "showSeparateAxis": false, | ||
338 | + "axisPosition": "left", | ||
339 | + "thresholds": [ | ||
340 | + { | ||
341 | + "thresholdValueSource": "predefinedValue" | ||
342 | + } | ||
343 | + ], | ||
344 | + "comparisonSettings": { | ||
345 | + "showValuesForComparison": true | ||
346 | + } | ||
347 | + }, | ||
348 | + "_hash": 0.2679547062508352 | ||
349 | + } | ||
350 | + ], | ||
351 | + "entityAliasId": "140f23dd-e3a0-ed98-6189-03c49d2d8018" | ||
352 | + } | ||
353 | + ], | ||
354 | + "timewindow": { | ||
355 | + "realtime": { | ||
356 | + "interval": 1000, | ||
357 | + "timewindowMs": 300000 | ||
358 | + }, | ||
359 | + "aggregation": { | ||
360 | + "type": "NONE", | ||
361 | + "limit": 8640 | ||
362 | + }, | ||
363 | + "hideInterval": false, | ||
364 | + "hideAggregation": false, | ||
365 | + "hideAggInterval": false | ||
366 | + }, | ||
367 | + "showTitle": true, | ||
368 | + "backgroundColor": "#fff", | ||
369 | + "color": "rgba(0, 0, 0, 0.87)", | ||
370 | + "padding": "8px", | ||
371 | + "settings": { | ||
372 | + "shadowSize": 4, | ||
373 | + "fontColor": "#545454", | ||
374 | + "fontSize": 10, | ||
375 | + "xaxis": { | ||
376 | + "showLabels": true, | ||
377 | + "color": "#545454" | ||
378 | + }, | ||
379 | + "yaxis": { | ||
380 | + "showLabels": true, | ||
381 | + "color": "#545454" | ||
382 | + }, | ||
383 | + "grid": { | ||
384 | + "color": "#545454", | ||
385 | + "tickColor": "#DDDDDD", | ||
386 | + "verticalLines": true, | ||
387 | + "horizontalLines": true, | ||
388 | + "outlineWidth": 1 | ||
389 | + }, | ||
390 | + "stack": false, | ||
391 | + "tooltipIndividual": false, | ||
392 | + "timeForComparison": "months", | ||
393 | + "xaxisSecond": { | ||
394 | + "axisPosition": "top", | ||
395 | + "showLabels": true | ||
396 | + } | ||
397 | + }, | ||
398 | + "title": "Processing Failures and Timeouts", | ||
399 | + "dropShadow": true, | ||
400 | + "enableFullscreen": true, | ||
401 | + "titleStyle": { | ||
402 | + "fontSize": "16px", | ||
403 | + "fontWeight": 400 | ||
404 | + }, | ||
405 | + "mobileHeight": null, | ||
406 | + "showTitleIcon": false, | ||
407 | + "titleIcon": null, | ||
408 | + "iconColor": "rgba(0, 0, 0, 0.87)", | ||
409 | + "iconSize": "24px", | ||
410 | + "titleTooltip": "", | ||
411 | + "widgetStyle": {}, | ||
412 | + "useDashboardTimewindow": false, | ||
413 | + "displayTimewindow": true, | ||
414 | + "showLegend": true, | ||
415 | + "actions": {}, | ||
416 | + "legendConfig": { | ||
417 | + "direction": "column", | ||
418 | + "position": "bottom", | ||
419 | + "showMin": true, | ||
420 | + "showMax": true, | ||
421 | + "showAvg": false, | ||
422 | + "showTotal": true | ||
423 | + } | ||
424 | + }, | ||
425 | + "id": "ad3f1417-87a8-750e-fc67-49a2de1466d4" | ||
426 | + } | ||
427 | + }, | ||
428 | + "states": { | ||
429 | + "default": { | ||
430 | + "name": "Rule Engine Statistics", | ||
431 | + "root": true, | ||
432 | + "layouts": { | ||
433 | + "main": { | ||
434 | + "widgets": { | ||
435 | + "81987f19-3eac-e4ce-b790-d96e9b54d9a0": { | ||
436 | + "sizeX": 12, | ||
437 | + "sizeY": 7, | ||
438 | + "mobileHeight": null, | ||
439 | + "row": 0, | ||
440 | + "col": 0 | ||
441 | + }, | ||
442 | + "5eb79712-5c24-3060-7e4f-6af36b8f842d": { | ||
443 | + "sizeX": 24, | ||
444 | + "sizeY": 5, | ||
445 | + "row": 7, | ||
446 | + "col": 0 | ||
447 | + }, | ||
448 | + "ad3f1417-87a8-750e-fc67-49a2de1466d4": { | ||
449 | + "sizeX": 12, | ||
450 | + "sizeY": 7, | ||
451 | + "mobileHeight": null, | ||
452 | + "row": 0, | ||
453 | + "col": 12 | ||
454 | + } | ||
455 | + }, | ||
456 | + "gridSettings": { | ||
457 | + "backgroundColor": "#eeeeee", | ||
458 | + "color": "rgba(0,0,0,0.870588)", | ||
459 | + "columns": 24, | ||
460 | + "margins": [ | ||
461 | + 10, | ||
462 | + 10 | ||
463 | + ], | ||
464 | + "backgroundSizeMode": "100%", | ||
465 | + "autoFillHeight": true, | ||
466 | + "mobileAutoFillHeight": false, | ||
467 | + "mobileRowHeight": 70 | ||
468 | + } | ||
469 | + } | ||
470 | + } | ||
471 | + } | ||
472 | + }, | ||
473 | + "entityAliases": { | ||
474 | + "140f23dd-e3a0-ed98-6189-03c49d2d8018": { | ||
475 | + "id": "140f23dd-e3a0-ed98-6189-03c49d2d8018", | ||
476 | + "alias": "TbServiceQueues", | ||
477 | + "filter": { | ||
478 | + "type": "assetType", | ||
479 | + "resolveMultiple": true, | ||
480 | + "assetType": "TbServiceQueue", | ||
481 | + "assetNameFilter": "" | ||
482 | + } | ||
483 | + } | ||
484 | + }, | ||
485 | + "timewindow": { | ||
486 | + "displayValue": "", | ||
487 | + "selectedTab": 0, | ||
488 | + "hideInterval": false, | ||
489 | + "hideAggregation": false, | ||
490 | + "hideAggInterval": false, | ||
491 | + "realtime": { | ||
492 | + "interval": 1000, | ||
493 | + "timewindowMs": 60000 | ||
494 | + }, | ||
495 | + "history": { | ||
496 | + "historyType": 0, | ||
497 | + "interval": 1000, | ||
498 | + "timewindowMs": 60000, | ||
499 | + "fixedTimewindow": { | ||
500 | + "startTimeMs": 1586176634823, | ||
501 | + "endTimeMs": 1586263034823 | ||
502 | + } | ||
503 | + }, | ||
504 | + "aggregation": { | ||
505 | + "type": "AVG", | ||
506 | + "limit": 25000 | ||
507 | + } | ||
508 | + }, | ||
509 | + "settings": { | ||
510 | + "stateControllerId": "entity", | ||
511 | + "showTitle": false, | ||
512 | + "showDashboardsSelect": true, | ||
513 | + "showEntitiesSelect": true, | ||
514 | + "showDashboardTimewindow": true, | ||
515 | + "showDashboardExport": true, | ||
516 | + "toolbarAlwaysOpen": true | ||
517 | + } | ||
518 | + }, | ||
519 | + "name": "Rule Engine Statistics" | ||
520 | +} |
@@ -123,3 +123,28 @@ BEGIN | @@ -123,3 +123,28 @@ BEGIN | ||
123 | END LOOP; | 123 | END LOOP; |
124 | END | 124 | END |
125 | $$; | 125 | $$; |
126 | + | ||
127 | +CREATE OR REPLACE PROCEDURE cleanup_events_by_ttl(IN ttl bigint, IN debug_ttl bigint, INOUT deleted bigint) | ||
128 | + LANGUAGE plpgsql AS | ||
129 | +$$ | ||
130 | +DECLARE | ||
131 | + ttl_ts bigint; | ||
132 | + debug_ttl_ts bigint; | ||
133 | + ttl_deleted_count bigint DEFAULT 0; | ||
134 | + debug_ttl_deleted_count bigint DEFAULT 0; | ||
135 | +BEGIN | ||
136 | + IF ttl > 0 THEN | ||
137 | + ttl_ts := (EXTRACT(EPOCH FROM current_timestamp) * 1000 - ttl::bigint * 1000)::bigint; | ||
138 | + EXECUTE format( | ||
139 | + 'WITH deleted AS (DELETE FROM event WHERE ts < %L::bigint AND (event_type != %L::varchar AND event_type != %L::varchar) RETURNING *) SELECT count(*) FROM deleted', ttl_ts, 'DEBUG_RULE_NODE', 'DEBUG_RULE_CHAIN') into ttl_deleted_count; | ||
140 | + END IF; | ||
141 | + IF debug_ttl > 0 THEN | ||
142 | + debug_ttl_ts := (EXTRACT(EPOCH FROM current_timestamp) * 1000 - debug_ttl::bigint * 1000)::bigint; | ||
143 | + EXECUTE format( | ||
144 | + 'WITH deleted AS (DELETE FROM event WHERE ts < %L::bigint AND (event_type = %L::varchar OR event_type = %L::varchar) RETURNING *) SELECT count(*) FROM deleted', debug_ttl_ts, 'DEBUG_RULE_NODE', 'DEBUG_RULE_CHAIN') into debug_ttl_deleted_count; | ||
145 | + END IF; | ||
146 | + RAISE NOTICE 'Events removed by ttl: %', ttl_deleted_count; | ||
147 | + RAISE NOTICE 'Debug Events removed by ttl: %', debug_ttl_deleted_count; | ||
148 | + deleted := ttl_deleted_count + debug_ttl_deleted_count; | ||
149 | +END | ||
150 | +$$; |
@@ -32,12 +32,10 @@ import lombok.Setter; | @@ -32,12 +32,10 @@ import lombok.Setter; | ||
32 | import lombok.extern.slf4j.Slf4j; | 32 | import lombok.extern.slf4j.Slf4j; |
33 | import org.springframework.beans.factory.annotation.Autowired; | 33 | import org.springframework.beans.factory.annotation.Autowired; |
34 | import org.springframework.beans.factory.annotation.Value; | 34 | import org.springframework.beans.factory.annotation.Value; |
35 | -import org.springframework.context.annotation.Lazy; | ||
36 | import org.springframework.data.redis.core.RedisTemplate; | 35 | import org.springframework.data.redis.core.RedisTemplate; |
37 | import org.springframework.scheduling.annotation.Scheduled; | 36 | import org.springframework.scheduling.annotation.Scheduled; |
38 | import org.springframework.stereotype.Component; | 37 | import org.springframework.stereotype.Component; |
39 | import org.thingsboard.rule.engine.api.MailService; | 38 | import org.thingsboard.rule.engine.api.MailService; |
40 | -import org.thingsboard.rule.engine.api.RuleChainTransactionService; | ||
41 | import org.thingsboard.server.actors.service.ActorService; | 39 | import org.thingsboard.server.actors.service.ActorService; |
42 | import org.thingsboard.server.actors.tenant.DebugTbRateLimits; | 40 | import org.thingsboard.server.actors.tenant.DebugTbRateLimits; |
43 | import org.thingsboard.server.common.data.DataConstants; | 41 | import org.thingsboard.server.common.data.DataConstants; |
@@ -45,10 +43,11 @@ import org.thingsboard.server.common.data.Event; | @@ -45,10 +43,11 @@ import org.thingsboard.server.common.data.Event; | ||
45 | import org.thingsboard.server.common.data.id.EntityId; | 43 | import org.thingsboard.server.common.data.id.EntityId; |
46 | import org.thingsboard.server.common.data.id.TenantId; | 44 | import org.thingsboard.server.common.data.id.TenantId; |
47 | import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; | 45 | import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; |
46 | +import org.thingsboard.server.common.msg.TbActorMsg; | ||
48 | import org.thingsboard.server.common.msg.TbMsg; | 47 | import org.thingsboard.server.common.msg.TbMsg; |
49 | -import org.thingsboard.server.common.msg.cluster.ServerAddress; | 48 | +import org.thingsboard.server.common.msg.queue.ServiceType; |
49 | +import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; | ||
50 | import org.thingsboard.server.common.msg.tools.TbRateLimits; | 50 | import org.thingsboard.server.common.msg.tools.TbRateLimits; |
51 | -import org.thingsboard.server.common.transport.auth.DeviceAuthService; | ||
52 | import org.thingsboard.server.dao.alarm.AlarmService; | 51 | import org.thingsboard.server.dao.alarm.AlarmService; |
53 | import org.thingsboard.server.dao.asset.AssetService; | 52 | import org.thingsboard.server.dao.asset.AssetService; |
54 | import org.thingsboard.server.dao.attributes.AttributesService; | 53 | import org.thingsboard.server.dao.attributes.AttributesService; |
@@ -65,24 +64,23 @@ import org.thingsboard.server.dao.rule.RuleChainService; | @@ -65,24 +64,23 @@ import org.thingsboard.server.dao.rule.RuleChainService; | ||
65 | import org.thingsboard.server.dao.tenant.TenantService; | 64 | import org.thingsboard.server.dao.tenant.TenantService; |
66 | import org.thingsboard.server.dao.timeseries.TimeseriesService; | 65 | import org.thingsboard.server.dao.timeseries.TimeseriesService; |
67 | import org.thingsboard.server.dao.user.UserService; | 66 | import org.thingsboard.server.dao.user.UserService; |
68 | -import org.thingsboard.server.kafka.TbNodeIdProvider; | ||
69 | -import org.thingsboard.server.service.cluster.discovery.DiscoveryService; | ||
70 | -import org.thingsboard.server.service.cluster.routing.ClusterRoutingService; | ||
71 | -import org.thingsboard.server.service.cluster.rpc.ClusterRpcService; | 67 | +import org.thingsboard.server.queue.discovery.PartitionService; |
68 | +import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; | ||
72 | import org.thingsboard.server.service.component.ComponentDiscoveryService; | 69 | import org.thingsboard.server.service.component.ComponentDiscoveryService; |
73 | import org.thingsboard.server.service.encoding.DataDecodingEncodingService; | 70 | import org.thingsboard.server.service.encoding.DataDecodingEncodingService; |
74 | -import org.thingsboard.server.service.executors.ClusterRpcCallbackExecutorService; | ||
75 | import org.thingsboard.server.service.executors.DbCallbackExecutorService; | 71 | import org.thingsboard.server.service.executors.DbCallbackExecutorService; |
76 | import org.thingsboard.server.service.executors.ExternalCallExecutorService; | 72 | import org.thingsboard.server.service.executors.ExternalCallExecutorService; |
77 | import org.thingsboard.server.service.executors.SharedEventLoopGroupService; | 73 | import org.thingsboard.server.service.executors.SharedEventLoopGroupService; |
78 | import org.thingsboard.server.service.mail.MailExecutorService; | 74 | import org.thingsboard.server.service.mail.MailExecutorService; |
79 | -import org.thingsboard.server.service.rpc.DeviceRpcService; | 75 | +import org.thingsboard.server.service.queue.TbClusterService; |
76 | +import org.thingsboard.server.service.rpc.TbCoreDeviceRpcService; | ||
77 | +import org.thingsboard.server.service.rpc.TbRuleEngineDeviceRpcService; | ||
80 | import org.thingsboard.server.service.script.JsExecutorService; | 78 | import org.thingsboard.server.service.script.JsExecutorService; |
81 | import org.thingsboard.server.service.script.JsInvokeService; | 79 | import org.thingsboard.server.service.script.JsInvokeService; |
82 | import org.thingsboard.server.service.session.DeviceSessionCacheService; | 80 | import org.thingsboard.server.service.session.DeviceSessionCacheService; |
83 | import org.thingsboard.server.service.state.DeviceStateService; | 81 | import org.thingsboard.server.service.state.DeviceStateService; |
84 | import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; | 82 | import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; |
85 | -import org.thingsboard.server.service.transport.RuleEngineTransportService; | 83 | +import org.thingsboard.server.service.transport.TbCoreToTransportService; |
86 | 84 | ||
87 | import javax.annotation.Nullable; | 85 | import javax.annotation.Nullable; |
88 | import java.io.IOException; | 86 | import java.io.IOException; |
@@ -106,13 +104,14 @@ public class ActorSystemContext { | @@ -106,13 +104,14 @@ public class ActorSystemContext { | ||
106 | return debugPerTenantLimits; | 104 | return debugPerTenantLimits; |
107 | } | 105 | } |
108 | 106 | ||
107 | + @Autowired | ||
109 | @Getter | 108 | @Getter |
110 | @Setter | 109 | @Setter |
111 | - private ActorService actorService; | 110 | + private TbServiceInfoProvider serviceInfoProvider; |
112 | 111 | ||
113 | - @Autowired | ||
114 | @Getter | 112 | @Getter |
115 | - private DiscoveryService discoveryService; | 113 | + @Setter |
114 | + private ActorService actorService; | ||
116 | 115 | ||
117 | @Autowired | 116 | @Autowired |
118 | @Getter | 117 | @Getter |
@@ -121,22 +120,10 @@ public class ActorSystemContext { | @@ -121,22 +120,10 @@ public class ActorSystemContext { | ||
121 | 120 | ||
122 | @Autowired | 121 | @Autowired |
123 | @Getter | 122 | @Getter |
124 | - private ClusterRoutingService routingService; | ||
125 | - | ||
126 | - @Autowired | ||
127 | - @Getter | ||
128 | - private ClusterRpcService rpcService; | ||
129 | - | ||
130 | - @Autowired | ||
131 | - @Getter | ||
132 | private DataDecodingEncodingService encodingService; | 123 | private DataDecodingEncodingService encodingService; |
133 | 124 | ||
134 | @Autowired | 125 | @Autowired |
135 | @Getter | 126 | @Getter |
136 | - private DeviceAuthService deviceAuthService; | ||
137 | - | ||
138 | - @Autowired | ||
139 | - @Getter | ||
140 | private DeviceService deviceService; | 127 | private DeviceService deviceService; |
141 | 128 | ||
142 | @Autowired | 129 | @Autowired |
@@ -164,6 +151,13 @@ public class ActorSystemContext { | @@ -164,6 +151,13 @@ public class ActorSystemContext { | ||
164 | private RuleChainService ruleChainService; | 151 | private RuleChainService ruleChainService; |
165 | 152 | ||
166 | @Autowired | 153 | @Autowired |
154 | + private PartitionService partitionService; | ||
155 | + | ||
156 | + @Autowired | ||
157 | + @Getter | ||
158 | + private TbClusterService clusterService; | ||
159 | + | ||
160 | + @Autowired | ||
167 | @Getter | 161 | @Getter |
168 | private TimeseriesService tsService; | 162 | private TimeseriesService tsService; |
169 | 163 | ||
@@ -197,10 +191,6 @@ public class ActorSystemContext { | @@ -197,10 +191,6 @@ public class ActorSystemContext { | ||
197 | 191 | ||
198 | @Autowired | 192 | @Autowired |
199 | @Getter | 193 | @Getter |
200 | - private DeviceRpcService deviceRpcService; | ||
201 | - | ||
202 | - @Autowired | ||
203 | - @Getter | ||
204 | private JsInvokeService jsSandbox; | 194 | private JsInvokeService jsSandbox; |
205 | 195 | ||
206 | @Autowired | 196 | @Autowired |
@@ -213,10 +203,6 @@ public class ActorSystemContext { | @@ -213,10 +203,6 @@ public class ActorSystemContext { | ||
213 | 203 | ||
214 | @Autowired | 204 | @Autowired |
215 | @Getter | 205 | @Getter |
216 | - private ClusterRpcCallbackExecutorService clusterRpcCallbackExecutor; | ||
217 | - | ||
218 | - @Autowired | ||
219 | - @Getter | ||
220 | private DbCallbackExecutorService dbCallbackExecutor; | 206 | private DbCallbackExecutorService dbCallbackExecutor; |
221 | 207 | ||
222 | @Autowired | 208 | @Autowired |
@@ -231,27 +217,32 @@ public class ActorSystemContext { | @@ -231,27 +217,32 @@ public class ActorSystemContext { | ||
231 | @Getter | 217 | @Getter |
232 | private MailService mailService; | 218 | private MailService mailService; |
233 | 219 | ||
234 | - @Autowired | 220 | + //TODO: separate context for TbCore and TbRuleEngine |
221 | + @Autowired(required = false) | ||
235 | @Getter | 222 | @Getter |
236 | private DeviceStateService deviceStateService; | 223 | private DeviceStateService deviceStateService; |
237 | 224 | ||
238 | - @Autowired | 225 | + @Autowired(required = false) |
239 | @Getter | 226 | @Getter |
240 | private DeviceSessionCacheService deviceSessionCacheService; | 227 | private DeviceSessionCacheService deviceSessionCacheService; |
241 | 228 | ||
242 | - @Lazy | ||
243 | - @Autowired | 229 | + @Autowired(required = false) |
244 | @Getter | 230 | @Getter |
245 | - private RuleEngineTransportService ruleEngineTransportService; | 231 | + private TbCoreToTransportService tbCoreToTransportService; |
246 | 232 | ||
247 | - @Lazy | ||
248 | - @Autowired | 233 | + /** |
234 | + * The following Service will be null if we operate in tb-core mode | ||
235 | + */ | ||
236 | + @Autowired(required = false) | ||
249 | @Getter | 237 | @Getter |
250 | - private RuleChainTransactionService ruleChainTransactionService; | 238 | + private TbRuleEngineDeviceRpcService tbRuleEngineDeviceRpcService; |
251 | 239 | ||
252 | - @Value("${cluster.partition_id}") | 240 | + /** |
241 | + * The following Service will be null if we operate in tb-rule-engine mode | ||
242 | + */ | ||
243 | + @Autowired(required = false) | ||
253 | @Getter | 244 | @Getter |
254 | - private long queuePartitionId; | 245 | + private TbCoreDeviceRpcService tbCoreDeviceRpcService; |
255 | 246 | ||
256 | @Value("${actors.session.max_concurrent_sessions_per_device:1}") | 247 | @Value("${actors.session.max_concurrent_sessions_per_device:1}") |
257 | @Getter | 248 | @Getter |
@@ -269,10 +260,6 @@ public class ActorSystemContext { | @@ -269,10 +260,6 @@ public class ActorSystemContext { | ||
269 | @Getter | 260 | @Getter |
270 | private long queuePersistenceTimeout; | 261 | private long queuePersistenceTimeout; |
271 | 262 | ||
272 | - @Value("${actors.client_side_rpc.timeout}") | ||
273 | - @Getter | ||
274 | - private long clientSideRpcTimeout; | ||
275 | - | ||
276 | @Value("${actors.rule.chain.error_persist_frequency}") | 263 | @Value("${actors.rule.chain.error_persist_frequency}") |
277 | @Getter | 264 | @Getter |
278 | private long ruleChainErrorPersistFrequency; | 265 | private long ruleChainErrorPersistFrequency; |
@@ -334,11 +321,6 @@ public class ActorSystemContext { | @@ -334,11 +321,6 @@ public class ActorSystemContext { | ||
334 | @Setter | 321 | @Setter |
335 | private ActorSystem actorSystem; | 322 | private ActorSystem actorSystem; |
336 | 323 | ||
337 | - @Autowired | ||
338 | - @Getter | ||
339 | - private TbNodeIdProvider nodeIdProvider; | ||
340 | - | ||
341 | - @Getter | ||
342 | @Setter | 324 | @Setter |
343 | private ActorRef appActor; | 325 | private ActorRef appActor; |
344 | 326 | ||
@@ -365,6 +347,8 @@ public class ActorSystemContext { | @@ -365,6 +347,8 @@ public class ActorSystemContext { | ||
365 | config = ConfigFactory.parseResources(AKKA_CONF_FILE_NAME).withFallback(ConfigFactory.load()); | 347 | config = ConfigFactory.parseResources(AKKA_CONF_FILE_NAME).withFallback(ConfigFactory.load()); |
366 | } | 348 | } |
367 | 349 | ||
350 | + | ||
351 | + | ||
368 | public Scheduler getScheduler() { | 352 | public Scheduler getScheduler() { |
369 | return actorSystem.scheduler(); | 353 | return actorSystem.scheduler(); |
370 | } | 354 | } |
@@ -374,7 +358,7 @@ public class ActorSystemContext { | @@ -374,7 +358,7 @@ public class ActorSystemContext { | ||
374 | event.setTenantId(tenantId); | 358 | event.setTenantId(tenantId); |
375 | event.setEntityId(entityId); | 359 | event.setEntityId(entityId); |
376 | event.setType(DataConstants.ERROR); | 360 | event.setType(DataConstants.ERROR); |
377 | - event.setBody(toBodyJson(discoveryService.getCurrentServer().getServerAddress(), method, toString(e))); | 361 | + event.setBody(toBodyJson(serviceInfoProvider.getServiceInfo().getServiceId(), method, toString(e))); |
378 | persistEvent(event); | 362 | persistEvent(event); |
379 | } | 363 | } |
380 | 364 | ||
@@ -383,7 +367,7 @@ public class ActorSystemContext { | @@ -383,7 +367,7 @@ public class ActorSystemContext { | ||
383 | event.setTenantId(tenantId); | 367 | event.setTenantId(tenantId); |
384 | event.setEntityId(entityId); | 368 | event.setEntityId(entityId); |
385 | event.setType(DataConstants.LC_EVENT); | 369 | event.setType(DataConstants.LC_EVENT); |
386 | - event.setBody(toBodyJson(discoveryService.getCurrentServer().getServerAddress(), lcEvent, Optional.ofNullable(e))); | 370 | + event.setBody(toBodyJson(serviceInfoProvider.getServiceInfo().getServiceId(), lcEvent, Optional.ofNullable(e))); |
387 | persistEvent(event); | 371 | persistEvent(event); |
388 | } | 372 | } |
389 | 373 | ||
@@ -397,8 +381,8 @@ public class ActorSystemContext { | @@ -397,8 +381,8 @@ public class ActorSystemContext { | ||
397 | return sw.toString(); | 381 | return sw.toString(); |
398 | } | 382 | } |
399 | 383 | ||
400 | - private JsonNode toBodyJson(ServerAddress server, ComponentLifecycleEvent event, Optional<Exception> e) { | ||
401 | - ObjectNode node = mapper.createObjectNode().put("server", server.toString()).put("event", event.name()); | 384 | + private JsonNode toBodyJson(String serviceId, ComponentLifecycleEvent event, Optional<Exception> e) { |
385 | + ObjectNode node = mapper.createObjectNode().put("server", serviceId).put("event", event.name()); | ||
402 | if (e.isPresent()) { | 386 | if (e.isPresent()) { |
403 | node = node.put("success", false); | 387 | node = node.put("success", false); |
404 | node = node.put("error", toString(e.get())); | 388 | node = node.put("error", toString(e.get())); |
@@ -408,12 +392,21 @@ public class ActorSystemContext { | @@ -408,12 +392,21 @@ public class ActorSystemContext { | ||
408 | return node; | 392 | return node; |
409 | } | 393 | } |
410 | 394 | ||
411 | - private JsonNode toBodyJson(ServerAddress server, String method, String body) { | ||
412 | - return mapper.createObjectNode().put("server", server.toString()).put("method", method).put("error", body); | 395 | + private JsonNode toBodyJson(String serviceId, String method, String body) { |
396 | + return mapper.createObjectNode().put("server", serviceId).put("method", method).put("error", body); | ||
413 | } | 397 | } |
414 | 398 | ||
415 | - public String getServerAddress() { | ||
416 | - return discoveryService.getCurrentServer().getServerAddress().toString(); | 399 | + public TopicPartitionInfo resolve(ServiceType serviceType, TenantId tenantId, EntityId entityId) { |
400 | + return partitionService.resolve(serviceType, tenantId, entityId); | ||
401 | + } | ||
402 | + | ||
403 | + public TopicPartitionInfo resolve(ServiceType serviceType, String queueName, TenantId tenantId, EntityId entityId) { | ||
404 | + return partitionService.resolve(serviceType, queueName, tenantId, entityId); | ||
405 | + } | ||
406 | + | ||
407 | + | ||
408 | + public String getServiceId() { | ||
409 | + return serviceInfoProvider.getServiceId(); | ||
417 | } | 410 | } |
418 | 411 | ||
419 | public void persistDebugInput(TenantId tenantId, EntityId entityId, TbMsg tbMsg, String relationType) { | 412 | public void persistDebugInput(TenantId tenantId, EntityId entityId, TbMsg tbMsg, String relationType) { |
@@ -444,7 +437,7 @@ public class ActorSystemContext { | @@ -444,7 +437,7 @@ public class ActorSystemContext { | ||
444 | 437 | ||
445 | ObjectNode node = mapper.createObjectNode() | 438 | ObjectNode node = mapper.createObjectNode() |
446 | .put("type", type) | 439 | .put("type", type) |
447 | - .put("server", getServerAddress()) | 440 | + .put("server", getServiceId()) |
448 | .put("entityId", tbMsg.getOriginator().getId().toString()) | 441 | .put("entityId", tbMsg.getOriginator().getId().toString()) |
449 | .put("entityName", tbMsg.getOriginator().getEntityType().name()) | 442 | .put("entityName", tbMsg.getOriginator().getEntityType().name()) |
450 | .put("msgId", tbMsg.getId().toString()) | 443 | .put("msgId", tbMsg.getId().toString()) |
@@ -504,7 +497,7 @@ public class ActorSystemContext { | @@ -504,7 +497,7 @@ public class ActorSystemContext { | ||
504 | 497 | ||
505 | ObjectNode node = mapper.createObjectNode() | 498 | ObjectNode node = mapper.createObjectNode() |
506 | //todo: what fields are needed here? | 499 | //todo: what fields are needed here? |
507 | - .put("server", getServerAddress()) | 500 | + .put("server", getServiceId()) |
508 | .put("message", "Reached debug mode rate limit!"); | 501 | .put("message", "Reached debug mode rate limit!"); |
509 | 502 | ||
510 | if (error != null) { | 503 | if (error != null) { |
@@ -530,4 +523,7 @@ public class ActorSystemContext { | @@ -530,4 +523,7 @@ public class ActorSystemContext { | ||
530 | return Exception.class.isInstance(error) ? (Exception) error : new Exception(error); | 523 | return Exception.class.isInstance(error) ? (Exception) error : new Exception(error); |
531 | } | 524 | } |
532 | 525 | ||
526 | + public void tell(TbActorMsg tbActorMsg, ActorRef sender) { | ||
527 | + appActor.tell(tbActorMsg, sender); | ||
528 | + } | ||
533 | } | 529 | } |
@@ -20,19 +20,13 @@ import akka.actor.LocalActorRef; | @@ -20,19 +20,13 @@ import akka.actor.LocalActorRef; | ||
20 | import akka.actor.OneForOneStrategy; | 20 | import akka.actor.OneForOneStrategy; |
21 | import akka.actor.Props; | 21 | import akka.actor.Props; |
22 | import akka.actor.SupervisorStrategy; | 22 | import akka.actor.SupervisorStrategy; |
23 | -import akka.actor.SupervisorStrategy.Directive; | ||
24 | import akka.actor.Terminated; | 23 | import akka.actor.Terminated; |
25 | -import akka.event.Logging; | ||
26 | -import akka.event.LoggingAdapter; | ||
27 | -import akka.japi.Function; | ||
28 | import com.google.common.collect.BiMap; | 24 | import com.google.common.collect.BiMap; |
29 | import com.google.common.collect.HashBiMap; | 25 | import com.google.common.collect.HashBiMap; |
30 | -import lombok.extern.slf4j.Slf4j; | ||
31 | import org.thingsboard.server.actors.ActorSystemContext; | 26 | import org.thingsboard.server.actors.ActorSystemContext; |
32 | -import org.thingsboard.server.actors.ruleChain.RuleChainManagerActor; | 27 | +import org.thingsboard.server.actors.service.ContextAwareActor; |
33 | import org.thingsboard.server.actors.service.ContextBasedCreator; | 28 | import org.thingsboard.server.actors.service.ContextBasedCreator; |
34 | import org.thingsboard.server.actors.service.DefaultActorService; | 29 | import org.thingsboard.server.actors.service.DefaultActorService; |
35 | -import org.thingsboard.server.actors.shared.rulechain.SystemRuleChainManager; | ||
36 | import org.thingsboard.server.actors.tenant.TenantActor; | 30 | import org.thingsboard.server.actors.tenant.TenantActor; |
37 | import org.thingsboard.server.common.data.EntityType; | 31 | import org.thingsboard.server.common.data.EntityType; |
38 | import org.thingsboard.server.common.data.Tenant; | 32 | import org.thingsboard.server.common.data.Tenant; |
@@ -42,29 +36,32 @@ import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; | @@ -42,29 +36,32 @@ import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; | ||
42 | import org.thingsboard.server.common.msg.MsgType; | 36 | import org.thingsboard.server.common.msg.MsgType; |
43 | import org.thingsboard.server.common.msg.TbActorMsg; | 37 | import org.thingsboard.server.common.msg.TbActorMsg; |
44 | import org.thingsboard.server.common.msg.aware.TenantAwareMsg; | 38 | import org.thingsboard.server.common.msg.aware.TenantAwareMsg; |
45 | -import org.thingsboard.server.common.msg.cluster.SendToClusterMsg; | ||
46 | -import org.thingsboard.server.common.msg.cluster.ServerAddress; | ||
47 | import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; | 39 | import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; |
48 | -import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg; | 40 | +import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg; |
41 | +import org.thingsboard.server.common.msg.queue.RuleEngineException; | ||
42 | +import org.thingsboard.server.common.msg.queue.ServiceType; | ||
49 | import org.thingsboard.server.dao.model.ModelConstants; | 43 | import org.thingsboard.server.dao.model.ModelConstants; |
50 | import org.thingsboard.server.dao.tenant.TenantService; | 44 | import org.thingsboard.server.dao.tenant.TenantService; |
45 | +import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper; | ||
51 | import scala.concurrent.duration.Duration; | 46 | import scala.concurrent.duration.Duration; |
52 | 47 | ||
53 | -import java.util.HashMap; | ||
54 | -import java.util.Map; | 48 | +import java.util.HashSet; |
55 | import java.util.Optional; | 49 | import java.util.Optional; |
50 | +import java.util.Set; | ||
56 | 51 | ||
57 | -public class AppActor extends RuleChainManagerActor { | 52 | +public class AppActor extends ContextAwareActor { |
58 | 53 | ||
59 | private static final TenantId SYSTEM_TENANT = new TenantId(ModelConstants.NULL_UUID); | 54 | private static final TenantId SYSTEM_TENANT = new TenantId(ModelConstants.NULL_UUID); |
60 | private final TenantService tenantService; | 55 | private final TenantService tenantService; |
61 | private final BiMap<TenantId, ActorRef> tenantActors; | 56 | private final BiMap<TenantId, ActorRef> tenantActors; |
57 | + private final Set<TenantId> deletedTenants; | ||
62 | private boolean ruleChainsInitialized; | 58 | private boolean ruleChainsInitialized; |
63 | 59 | ||
64 | private AppActor(ActorSystemContext systemContext) { | 60 | private AppActor(ActorSystemContext systemContext) { |
65 | - super(systemContext, new SystemRuleChainManager(systemContext)); | 61 | + super(systemContext); |
66 | this.tenantService = systemContext.getTenantService(); | 62 | this.tenantService = systemContext.getTenantService(); |
67 | this.tenantActors = HashBiMap.create(); | 63 | this.tenantActors = HashBiMap.create(); |
64 | + this.deletedTenants = new HashSet<>(); | ||
68 | } | 65 | } |
69 | 66 | ||
70 | @Override | 67 | @Override |
@@ -79,7 +76,7 @@ public class AppActor extends RuleChainManagerActor { | @@ -79,7 +76,7 @@ public class AppActor extends RuleChainManagerActor { | ||
79 | @Override | 76 | @Override |
80 | protected boolean process(TbActorMsg msg) { | 77 | protected boolean process(TbActorMsg msg) { |
81 | if (!ruleChainsInitialized) { | 78 | if (!ruleChainsInitialized) { |
82 | - initRuleChainsAndTenantActors(); | 79 | + initTenantActors(); |
83 | ruleChainsInitialized = true; | 80 | ruleChainsInitialized = true; |
84 | if (msg.getMsgType() != MsgType.APP_INIT_MSG) { | 81 | if (msg.getMsgType() != MsgType.APP_INIT_MSG) { |
85 | log.warn("Rule Chains initialized by unexpected message: {}", msg); | 82 | log.warn("Rule Chains initialized by unexpected message: {}", msg); |
@@ -88,17 +85,14 @@ public class AppActor extends RuleChainManagerActor { | @@ -88,17 +85,14 @@ public class AppActor extends RuleChainManagerActor { | ||
88 | switch (msg.getMsgType()) { | 85 | switch (msg.getMsgType()) { |
89 | case APP_INIT_MSG: | 86 | case APP_INIT_MSG: |
90 | break; | 87 | break; |
91 | - case SEND_TO_CLUSTER_MSG: | ||
92 | - onPossibleClusterMsg((SendToClusterMsg) msg); | ||
93 | - break; | ||
94 | - case CLUSTER_EVENT_MSG: | 88 | + case PARTITION_CHANGE_MSG: |
95 | broadcast(msg); | 89 | broadcast(msg); |
96 | break; | 90 | break; |
97 | case COMPONENT_LIFE_CYCLE_MSG: | 91 | case COMPONENT_LIFE_CYCLE_MSG: |
98 | onComponentLifecycleMsg((ComponentLifecycleMsg) msg); | 92 | onComponentLifecycleMsg((ComponentLifecycleMsg) msg); |
99 | break; | 93 | break; |
100 | - case SERVICE_TO_RULE_ENGINE_MSG: | ||
101 | - onServiceToRuleEngineMsg((ServiceToRuleEngineMsg) msg); | 94 | + case QUEUE_TO_RULE_ENGINE_MSG: |
95 | + onQueueToRuleEngineMsg((QueueToRuleEngineMsg) msg); | ||
102 | break; | 96 | break; |
103 | case TRANSPORT_TO_DEVICE_ACTOR_MSG: | 97 | case TRANSPORT_TO_DEVICE_ACTOR_MSG: |
104 | case DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG: | 98 | case DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG: |
@@ -106,7 +100,6 @@ public class AppActor extends RuleChainManagerActor { | @@ -106,7 +100,6 @@ public class AppActor extends RuleChainManagerActor { | ||
106 | case DEVICE_NAME_OR_TYPE_UPDATE_TO_DEVICE_ACTOR_MSG: | 100 | case DEVICE_NAME_OR_TYPE_UPDATE_TO_DEVICE_ACTOR_MSG: |
107 | case DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG: | 101 | case DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG: |
108 | case SERVER_RPC_RESPONSE_TO_DEVICE_ACTOR_MSG: | 102 | case SERVER_RPC_RESPONSE_TO_DEVICE_ACTOR_MSG: |
109 | - case REMOTE_TO_RULE_CHAIN_TELL_NEXT_MSG: | ||
110 | onToDeviceActorMsg((TenantAwareMsg) msg); | 103 | onToDeviceActorMsg((TenantAwareMsg) msg); |
111 | break; | 104 | break; |
112 | default: | 105 | default: |
@@ -115,16 +108,30 @@ public class AppActor extends RuleChainManagerActor { | @@ -115,16 +108,30 @@ public class AppActor extends RuleChainManagerActor { | ||
115 | return true; | 108 | return true; |
116 | } | 109 | } |
117 | 110 | ||
118 | - private void initRuleChainsAndTenantActors() { | 111 | + private void initTenantActors() { |
119 | log.info("Starting main system actor."); | 112 | log.info("Starting main system actor."); |
120 | try { | 113 | try { |
121 | - initRuleChains(); | ||
122 | - if (systemContext.isTenantComponentsInitEnabled()) { | ||
123 | - PageDataIterable<Tenant> tenantIterator = new PageDataIterable<>(tenantService::findTenants, ENTITY_PACK_LIMIT); | ||
124 | - for (Tenant tenant : tenantIterator) { | 114 | + // This Service may be started for specific tenant only. |
115 | + Optional<TenantId> isolatedTenantId = systemContext.getServiceInfoProvider().getIsolatedTenant(); | ||
116 | + if (isolatedTenantId.isPresent()) { | ||
117 | + Tenant tenant = systemContext.getTenantService().findTenantById(isolatedTenantId.get()); | ||
118 | + if (tenant != null) { | ||
125 | log.debug("[{}] Creating tenant actor", tenant.getId()); | 119 | log.debug("[{}] Creating tenant actor", tenant.getId()); |
126 | getOrCreateTenantActor(tenant.getId()); | 120 | getOrCreateTenantActor(tenant.getId()); |
127 | log.debug("Tenant actor created."); | 121 | log.debug("Tenant actor created."); |
122 | + } else { | ||
123 | + log.error("[{}] Tenant with such ID does not exist", isolatedTenantId.get()); | ||
124 | + } | ||
125 | + } else if (systemContext.isTenantComponentsInitEnabled()) { | ||
126 | + PageDataIterable<Tenant> tenantIterator = new PageDataIterable<>(tenantService::findTenants, ENTITY_PACK_LIMIT); | ||
127 | + boolean isRuleEngine = systemContext.getServiceInfoProvider().isService(ServiceType.TB_RULE_ENGINE); | ||
128 | + boolean isCore = systemContext.getServiceInfoProvider().isService(ServiceType.TB_CORE); | ||
129 | + for (Tenant tenant : tenantIterator) { | ||
130 | + if (isCore || (isRuleEngine && !tenant.isIsolatedTbRuleEngine())) { | ||
131 | + log.debug("[{}] Creating tenant actor", tenant.getId()); | ||
132 | + getOrCreateTenantActor(tenant.getId()); | ||
133 | + log.debug("[{}] Tenant actor created.", tenant.getId()); | ||
134 | + } | ||
128 | } | 135 | } |
129 | } | 136 | } |
130 | log.info("Main system actor started."); | 137 | log.info("Main system actor started."); |
@@ -133,40 +140,33 @@ public class AppActor extends RuleChainManagerActor { | @@ -133,40 +140,33 @@ public class AppActor extends RuleChainManagerActor { | ||
133 | } | 140 | } |
134 | } | 141 | } |
135 | 142 | ||
136 | - private void onPossibleClusterMsg(SendToClusterMsg msg) { | ||
137 | - Optional<ServerAddress> address = systemContext.getRoutingService().resolveById(msg.getEntityId()); | ||
138 | - if (address.isPresent()) { | ||
139 | - systemContext.getRpcService().tell( | ||
140 | - systemContext.getEncodingService().convertToProtoDataMessage(address.get(), msg.getMsg())); | ||
141 | - } else { | ||
142 | - self().tell(msg.getMsg(), ActorRef.noSender()); | ||
143 | - } | ||
144 | - } | ||
145 | - | ||
146 | - private void onServiceToRuleEngineMsg(ServiceToRuleEngineMsg msg) { | 143 | + private void onQueueToRuleEngineMsg(QueueToRuleEngineMsg msg) { |
147 | if (SYSTEM_TENANT.equals(msg.getTenantId())) { | 144 | if (SYSTEM_TENANT.equals(msg.getTenantId())) { |
148 | -// this may be a notification about system entities created. | ||
149 | -// log.warn("[{}] Invalid service to rule engine msg called. System messages are not supported yet: {}", SYSTEM_TENANT, msg); | 145 | + msg.getTbMsg().getCallback().onFailure(new RuleEngineException("Message has system tenant id!")); |
150 | } else { | 146 | } else { |
151 | - getOrCreateTenantActor(msg.getTenantId()).tell(msg, self()); | 147 | + if (!deletedTenants.contains(msg.getTenantId())) { |
148 | + getOrCreateTenantActor(msg.getTenantId()).tell(msg, self()); | ||
149 | + } else { | ||
150 | + msg.getTbMsg().getCallback().onSuccess(); | ||
151 | + } | ||
152 | } | 152 | } |
153 | } | 153 | } |
154 | 154 | ||
155 | - @Override | ||
156 | protected void broadcast(Object msg) { | 155 | protected void broadcast(Object msg) { |
157 | - super.broadcast(msg); | ||
158 | tenantActors.values().forEach(actorRef -> actorRef.tell(msg, ActorRef.noSender())); | 156 | tenantActors.values().forEach(actorRef -> actorRef.tell(msg, ActorRef.noSender())); |
159 | } | 157 | } |
160 | 158 | ||
161 | private void onComponentLifecycleMsg(ComponentLifecycleMsg msg) { | 159 | private void onComponentLifecycleMsg(ComponentLifecycleMsg msg) { |
162 | ActorRef target = null; | 160 | ActorRef target = null; |
163 | if (SYSTEM_TENANT.equals(msg.getTenantId())) { | 161 | if (SYSTEM_TENANT.equals(msg.getTenantId())) { |
164 | - target = getEntityActorRef(msg.getEntityId()); | 162 | + log.warn("Message has system tenant id: {}", msg); |
165 | } else { | 163 | } else { |
166 | if (msg.getEntityId().getEntityType() == EntityType.TENANT | 164 | if (msg.getEntityId().getEntityType() == EntityType.TENANT |
167 | && msg.getEvent() == ComponentLifecycleEvent.DELETED) { | 165 | && msg.getEvent() == ComponentLifecycleEvent.DELETED) { |
168 | - log.debug("[{}] Handling tenant deleted notification: {}", msg.getTenantId(), msg); | ||
169 | - ActorRef tenantActor = tenantActors.remove(new TenantId(msg.getEntityId().getId())); | 166 | + log.info("[{}] Handling tenant deleted notification: {}", msg.getTenantId(), msg); |
167 | + TenantId tenantId = new TenantId(msg.getEntityId().getId()); | ||
168 | + deletedTenants.add(tenantId); | ||
169 | + ActorRef tenantActor = tenantActors.get(tenantId); | ||
170 | if (tenantActor != null) { | 170 | if (tenantActor != null) { |
171 | log.debug("[{}] Deleting tenant actor: {}", msg.getTenantId(), tenantActor); | 171 | log.debug("[{}] Deleting tenant actor: {}", msg.getTenantId(), tenantActor); |
172 | context().stop(tenantActor); | 172 | context().stop(tenantActor); |
@@ -183,16 +183,22 @@ public class AppActor extends RuleChainManagerActor { | @@ -183,16 +183,22 @@ public class AppActor extends RuleChainManagerActor { | ||
183 | } | 183 | } |
184 | 184 | ||
185 | private void onToDeviceActorMsg(TenantAwareMsg msg) { | 185 | private void onToDeviceActorMsg(TenantAwareMsg msg) { |
186 | - getOrCreateTenantActor(msg.getTenantId()).tell(msg, ActorRef.noSender()); | 186 | + if (!deletedTenants.contains(msg.getTenantId())) { |
187 | + getOrCreateTenantActor(msg.getTenantId()).tell(msg, ActorRef.noSender()); | ||
188 | + } else { | ||
189 | + if (msg instanceof TransportToDeviceActorMsgWrapper) { | ||
190 | + ((TransportToDeviceActorMsgWrapper) msg).getCallback().onSuccess(); | ||
191 | + } | ||
192 | + } | ||
187 | } | 193 | } |
188 | 194 | ||
189 | private ActorRef getOrCreateTenantActor(TenantId tenantId) { | 195 | private ActorRef getOrCreateTenantActor(TenantId tenantId) { |
190 | return tenantActors.computeIfAbsent(tenantId, k -> { | 196 | return tenantActors.computeIfAbsent(tenantId, k -> { |
191 | - log.debug("[{}] Creating tenant actor.", tenantId); | 197 | + log.info("[{}] Creating tenant actor.", tenantId); |
192 | ActorRef tenantActor = context().actorOf(Props.create(new TenantActor.ActorCreator(systemContext, tenantId)) | 198 | ActorRef tenantActor = context().actorOf(Props.create(new TenantActor.ActorCreator(systemContext, tenantId)) |
193 | .withDispatcher(DefaultActorService.CORE_DISPATCHER_NAME), tenantId.toString()); | 199 | .withDispatcher(DefaultActorService.CORE_DISPATCHER_NAME), tenantId.toString()); |
194 | context().watch(tenantActor); | 200 | context().watch(tenantActor); |
195 | - log.debug("[{}] Created tenant actor: {}.", tenantId, tenantActor); | 201 | + log.info("[{}] Created tenant actor: {}.", tenantId, tenantActor); |
196 | return tenantActor; | 202 | return tenantActor; |
197 | }); | 203 | }); |
198 | } | 204 | } |
@@ -22,10 +22,8 @@ import org.thingsboard.server.actors.service.ContextAwareActor; | @@ -22,10 +22,8 @@ import org.thingsboard.server.actors.service.ContextAwareActor; | ||
22 | import org.thingsboard.server.common.data.id.DeviceId; | 22 | import org.thingsboard.server.common.data.id.DeviceId; |
23 | import org.thingsboard.server.common.data.id.TenantId; | 23 | import org.thingsboard.server.common.data.id.TenantId; |
24 | import org.thingsboard.server.common.msg.TbActorMsg; | 24 | import org.thingsboard.server.common.msg.TbActorMsg; |
25 | -import org.thingsboard.server.common.msg.timeout.DeviceActorClientSideRpcTimeoutMsg; | ||
26 | import org.thingsboard.server.common.msg.timeout.DeviceActorServerSideRpcTimeoutMsg; | 25 | import org.thingsboard.server.common.msg.timeout.DeviceActorServerSideRpcTimeoutMsg; |
27 | import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg; | 26 | import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg; |
28 | -import org.thingsboard.server.service.rpc.ToServerRpcResponseActorMsg; | ||
29 | import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper; | 27 | import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper; |
30 | 28 | ||
31 | public class DeviceActor extends ContextAwareActor { | 29 | public class DeviceActor extends ContextAwareActor { |
@@ -49,6 +47,11 @@ public class DeviceActor extends ContextAwareActor { | @@ -49,6 +47,11 @@ public class DeviceActor extends ContextAwareActor { | ||
49 | } | 47 | } |
50 | 48 | ||
51 | @Override | 49 | @Override |
50 | + public void postStop() { | ||
51 | + | ||
52 | + } | ||
53 | + | ||
54 | + @Override | ||
52 | protected boolean process(TbActorMsg msg) { | 55 | protected boolean process(TbActorMsg msg) { |
53 | switch (msg.getMsgType()) { | 56 | switch (msg.getMsgType()) { |
54 | case TRANSPORT_TO_DEVICE_ACTOR_MSG: | 57 | case TRANSPORT_TO_DEVICE_ACTOR_MSG: |
@@ -66,15 +69,9 @@ public class DeviceActor extends ContextAwareActor { | @@ -66,15 +69,9 @@ public class DeviceActor extends ContextAwareActor { | ||
66 | case DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG: | 69 | case DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG: |
67 | processor.processRpcRequest(context(), (ToDeviceRpcRequestActorMsg) msg); | 70 | processor.processRpcRequest(context(), (ToDeviceRpcRequestActorMsg) msg); |
68 | break; | 71 | break; |
69 | - case SERVER_RPC_RESPONSE_TO_DEVICE_ACTOR_MSG: | ||
70 | - processor.processToServerRPCResponse(context(), (ToServerRpcResponseActorMsg) msg); | ||
71 | - break; | ||
72 | case DEVICE_ACTOR_SERVER_SIDE_RPC_TIMEOUT_MSG: | 72 | case DEVICE_ACTOR_SERVER_SIDE_RPC_TIMEOUT_MSG: |
73 | processor.processServerSideRpcTimeout(context(), (DeviceActorServerSideRpcTimeoutMsg) msg); | 73 | processor.processServerSideRpcTimeout(context(), (DeviceActorServerSideRpcTimeoutMsg) msg); |
74 | break; | 74 | break; |
75 | - case DEVICE_ACTOR_CLIENT_SIDE_RPC_TIMEOUT_MSG: | ||
76 | - processor.processClientSideRpcTimeout(context(), (DeviceActorClientSideRpcTimeoutMsg) msg); | ||
77 | - break; | ||
78 | case SESSION_TIMEOUT_MSG: | 75 | case SESSION_TIMEOUT_MSG: |
79 | processor.checkSessionsTimeout(); | 76 | processor.checkSessionsTimeout(); |
80 | break; | 77 | break; |
@@ -16,13 +16,10 @@ | @@ -16,13 +16,10 @@ | ||
16 | package org.thingsboard.server.actors.device; | 16 | package org.thingsboard.server.actors.device; |
17 | 17 | ||
18 | import akka.actor.ActorContext; | 18 | import akka.actor.ActorContext; |
19 | -import com.datastax.driver.core.utils.UUIDs; | ||
20 | import com.google.common.util.concurrent.FutureCallback; | 19 | import com.google.common.util.concurrent.FutureCallback; |
21 | import com.google.common.util.concurrent.Futures; | 20 | import com.google.common.util.concurrent.Futures; |
22 | import com.google.common.util.concurrent.ListenableFuture; | 21 | import com.google.common.util.concurrent.ListenableFuture; |
23 | import com.google.common.util.concurrent.MoreExecutors; | 22 | import com.google.common.util.concurrent.MoreExecutors; |
24 | -import com.google.gson.Gson; | ||
25 | -import com.google.gson.JsonObject; | ||
26 | import com.google.protobuf.InvalidProtocolBufferException; | 23 | import com.google.protobuf.InvalidProtocolBufferException; |
27 | import lombok.extern.slf4j.Slf4j; | 24 | import lombok.extern.slf4j.Slf4j; |
28 | import org.apache.commons.collections.CollectionUtils; | 25 | import org.apache.commons.collections.CollectionUtils; |
@@ -38,38 +35,34 @@ import org.thingsboard.server.common.data.kv.AttributeKey; | @@ -38,38 +35,34 @@ import org.thingsboard.server.common.data.kv.AttributeKey; | ||
38 | import org.thingsboard.server.common.data.kv.AttributeKvEntry; | 35 | import org.thingsboard.server.common.data.kv.AttributeKvEntry; |
39 | import org.thingsboard.server.common.data.kv.KvEntry; | 36 | import org.thingsboard.server.common.data.kv.KvEntry; |
40 | import org.thingsboard.server.common.data.rpc.ToDeviceRpcRequestBody; | 37 | import org.thingsboard.server.common.data.rpc.ToDeviceRpcRequestBody; |
41 | -import org.thingsboard.server.common.msg.TbMsg; | ||
42 | -import org.thingsboard.server.common.msg.TbMsgDataType; | ||
43 | import org.thingsboard.server.common.msg.TbMsgMetaData; | 38 | import org.thingsboard.server.common.msg.TbMsgMetaData; |
39 | +import org.thingsboard.server.common.msg.queue.TbCallback; | ||
44 | import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest; | 40 | import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest; |
45 | -import org.thingsboard.server.common.msg.session.SessionMsgType; | ||
46 | -import org.thingsboard.server.common.msg.timeout.DeviceActorClientSideRpcTimeoutMsg; | ||
47 | import org.thingsboard.server.common.msg.timeout.DeviceActorServerSideRpcTimeoutMsg; | 41 | import org.thingsboard.server.common.msg.timeout.DeviceActorServerSideRpcTimeoutMsg; |
48 | -import org.thingsboard.server.gen.transport.TransportProtos; | ||
49 | import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg; | 42 | import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg; |
50 | -import org.thingsboard.server.gen.transport.TransportProtos.DeviceActorToTransportMsg; | 43 | +import org.thingsboard.server.gen.transport.TransportProtos.DeviceSessionsCacheEntry; |
51 | import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeRequestMsg; | 44 | import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeRequestMsg; |
52 | import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeResponseMsg; | 45 | import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeResponseMsg; |
53 | import org.thingsboard.server.gen.transport.TransportProtos.KeyValueProto; | 46 | import org.thingsboard.server.gen.transport.TransportProtos.KeyValueProto; |
54 | import org.thingsboard.server.gen.transport.TransportProtos.KeyValueType; | 47 | import org.thingsboard.server.gen.transport.TransportProtos.KeyValueType; |
55 | -import org.thingsboard.server.gen.transport.TransportProtos.PostAttributeMsg; | ||
56 | -import org.thingsboard.server.gen.transport.TransportProtos.PostTelemetryMsg; | ||
57 | import org.thingsboard.server.gen.transport.TransportProtos.SessionCloseNotificationProto; | 48 | import org.thingsboard.server.gen.transport.TransportProtos.SessionCloseNotificationProto; |
58 | import org.thingsboard.server.gen.transport.TransportProtos.SessionEvent; | 49 | import org.thingsboard.server.gen.transport.TransportProtos.SessionEvent; |
59 | import org.thingsboard.server.gen.transport.TransportProtos.SessionEventMsg; | 50 | import org.thingsboard.server.gen.transport.TransportProtos.SessionEventMsg; |
60 | import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; | 51 | import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; |
52 | +import org.thingsboard.server.gen.transport.TransportProtos.SessionSubscriptionInfoProto; | ||
53 | +import org.thingsboard.server.gen.transport.TransportProtos.SessionType; | ||
61 | import org.thingsboard.server.gen.transport.TransportProtos.SubscribeToAttributeUpdatesMsg; | 54 | import org.thingsboard.server.gen.transport.TransportProtos.SubscribeToAttributeUpdatesMsg; |
62 | import org.thingsboard.server.gen.transport.TransportProtos.SubscribeToRPCMsg; | 55 | import org.thingsboard.server.gen.transport.TransportProtos.SubscribeToRPCMsg; |
56 | +import org.thingsboard.server.gen.transport.TransportProtos.SubscriptionInfoProto; | ||
63 | import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcRequestMsg; | 57 | import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcRequestMsg; |
64 | import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcResponseMsg; | 58 | import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcResponseMsg; |
59 | +import org.thingsboard.server.gen.transport.TransportProtos.ToServerRpcResponseMsg; | ||
60 | +import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; | ||
65 | import org.thingsboard.server.gen.transport.TransportProtos.TransportToDeviceActorMsg; | 61 | import org.thingsboard.server.gen.transport.TransportProtos.TransportToDeviceActorMsg; |
66 | -import org.thingsboard.server.gen.transport.TransportProtos.TsKvListProto; | ||
67 | import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto; | 62 | import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto; |
68 | import org.thingsboard.server.service.rpc.FromDeviceRpcResponse; | 63 | import org.thingsboard.server.service.rpc.FromDeviceRpcResponse; |
69 | import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg; | 64 | import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg; |
70 | -import org.thingsboard.server.service.rpc.ToServerRpcResponseActorMsg; | ||
71 | import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper; | 65 | import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper; |
72 | -import org.thingsboard.server.utils.JsonUtils; | ||
73 | 66 | ||
74 | import javax.annotation.Nullable; | 67 | import javax.annotation.Nullable; |
75 | import java.util.ArrayList; | 68 | import java.util.ArrayList; |
@@ -100,9 +93,6 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | @@ -100,9 +93,6 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | ||
100 | private final Map<UUID, SessionInfo> attributeSubscriptions; | 93 | private final Map<UUID, SessionInfo> attributeSubscriptions; |
101 | private final Map<UUID, SessionInfo> rpcSubscriptions; | 94 | private final Map<UUID, SessionInfo> rpcSubscriptions; |
102 | private final Map<Integer, ToDeviceRpcRequestMetadata> toDeviceRpcPendingMap; | 95 | private final Map<Integer, ToDeviceRpcRequestMetadata> toDeviceRpcPendingMap; |
103 | - private final Map<Integer, ToServerRpcRequestMetadata> toServerRpcPendingMap; | ||
104 | - | ||
105 | - private final Gson gson = new Gson(); | ||
106 | 96 | ||
107 | private int rpcSeq = 0; | 97 | private int rpcSeq = 0; |
108 | private String deviceName; | 98 | private String deviceName; |
@@ -117,7 +107,6 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | @@ -117,7 +107,6 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | ||
117 | this.attributeSubscriptions = new HashMap<>(); | 107 | this.attributeSubscriptions = new HashMap<>(); |
118 | this.rpcSubscriptions = new HashMap<>(); | 108 | this.rpcSubscriptions = new HashMap<>(); |
119 | this.toDeviceRpcPendingMap = new HashMap<>(); | 109 | this.toDeviceRpcPendingMap = new HashMap<>(); |
120 | - this.toServerRpcPendingMap = new HashMap<>(); | ||
121 | if (initAttributes()) { | 110 | if (initAttributes()) { |
122 | restoreSessions(); | 111 | restoreSessions(); |
123 | } | 112 | } |
@@ -153,7 +142,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | @@ -153,7 +142,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | ||
153 | Set<UUID> syncSessionSet = new HashSet<>(); | 142 | Set<UUID> syncSessionSet = new HashSet<>(); |
154 | rpcSubscriptions.forEach((key, value) -> { | 143 | rpcSubscriptions.forEach((key, value) -> { |
155 | sendToTransport(rpcRequest, key, value.getNodeId()); | 144 | sendToTransport(rpcRequest, key, value.getNodeId()); |
156 | - if (TransportProtos.SessionType.SYNC == value.getType()) { | 145 | + if (SessionType.SYNC == value.getType()) { |
157 | syncSessionSet.add(key); | 146 | syncSessionSet.add(key); |
158 | } | 147 | } |
159 | }); | 148 | }); |
@@ -161,7 +150,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | @@ -161,7 +150,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | ||
161 | 150 | ||
162 | if (request.isOneway() && sent) { | 151 | if (request.isOneway() && sent) { |
163 | log.debug("[{}] Rpc command response sent [{}]!", deviceId, request.getId()); | 152 | log.debug("[{}] Rpc command response sent [{}]!", deviceId, request.getId()); |
164 | - systemContext.getDeviceRpcService().processResponseToServerSideRPCRequestFromDeviceActor(new FromDeviceRpcResponse(msg.getMsg().getId(), null, null)); | 153 | + systemContext.getTbCoreDeviceRpcService().processRpcResponseFromDeviceActor(new FromDeviceRpcResponse(msg.getMsg().getId(), null, null)); |
165 | } else { | 154 | } else { |
166 | registerPendingRpcRequest(context, msg, sent, rpcRequest, timeout); | 155 | registerPendingRpcRequest(context, msg, sent, rpcRequest, timeout); |
167 | } | 156 | } |
@@ -182,16 +171,16 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | @@ -182,16 +171,16 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | ||
182 | ToDeviceRpcRequestMetadata requestMd = toDeviceRpcPendingMap.remove(msg.getId()); | 171 | ToDeviceRpcRequestMetadata requestMd = toDeviceRpcPendingMap.remove(msg.getId()); |
183 | if (requestMd != null) { | 172 | if (requestMd != null) { |
184 | log.debug("[{}] RPC request [{}] timeout detected!", deviceId, msg.getId()); | 173 | log.debug("[{}] RPC request [{}] timeout detected!", deviceId, msg.getId()); |
185 | - systemContext.getDeviceRpcService().processResponseToServerSideRPCRequestFromDeviceActor(new FromDeviceRpcResponse(requestMd.getMsg().getMsg().getId(), | 174 | + systemContext.getTbCoreDeviceRpcService().processRpcResponseFromDeviceActor(new FromDeviceRpcResponse(requestMd.getMsg().getMsg().getId(), |
186 | null, requestMd.isSent() ? RpcError.TIMEOUT : RpcError.NO_ACTIVE_CONNECTION)); | 175 | null, requestMd.isSent() ? RpcError.TIMEOUT : RpcError.NO_ACTIVE_CONNECTION)); |
187 | } | 176 | } |
188 | } | 177 | } |
189 | 178 | ||
190 | private void sendPendingRequests(ActorContext context, UUID sessionId, SessionInfoProto sessionInfo) { | 179 | private void sendPendingRequests(ActorContext context, UUID sessionId, SessionInfoProto sessionInfo) { |
191 | - TransportProtos.SessionType sessionType = getSessionType(sessionId); | 180 | + SessionType sessionType = getSessionType(sessionId); |
192 | if (!toDeviceRpcPendingMap.isEmpty()) { | 181 | if (!toDeviceRpcPendingMap.isEmpty()) { |
193 | log.debug("[{}] Pushing {} pending RPC messages to new async session [{}]", deviceId, toDeviceRpcPendingMap.size(), sessionId); | 182 | log.debug("[{}] Pushing {} pending RPC messages to new async session [{}]", deviceId, toDeviceRpcPendingMap.size(), sessionId); |
194 | - if (sessionType == TransportProtos.SessionType.SYNC) { | 183 | + if (sessionType == SessionType.SYNC) { |
195 | log.debug("[{}] Cleanup sync rpc session [{}]", deviceId, sessionId); | 184 | log.debug("[{}] Cleanup sync rpc session [{}]", deviceId, sessionId); |
196 | rpcSubscriptions.remove(sessionId); | 185 | rpcSubscriptions.remove(sessionId); |
197 | } | 186 | } |
@@ -199,7 +188,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | @@ -199,7 +188,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | ||
199 | log.debug("[{}] No pending RPC messages for new async session [{}]", deviceId, sessionId); | 188 | log.debug("[{}] No pending RPC messages for new async session [{}]", deviceId, sessionId); |
200 | } | 189 | } |
201 | Set<Integer> sentOneWayIds = new HashSet<>(); | 190 | Set<Integer> sentOneWayIds = new HashSet<>(); |
202 | - if (sessionType == TransportProtos.SessionType.ASYNC) { | 191 | + if (sessionType == SessionType.ASYNC) { |
203 | toDeviceRpcPendingMap.entrySet().forEach(processPendingRpc(context, sessionId, sessionInfo.getNodeId(), sentOneWayIds)); | 192 | toDeviceRpcPendingMap.entrySet().forEach(processPendingRpc(context, sessionId, sessionInfo.getNodeId(), sentOneWayIds)); |
204 | } else { | 193 | } else { |
205 | toDeviceRpcPendingMap.entrySet().stream().findFirst().ifPresent(processPendingRpc(context, sessionId, sessionInfo.getNodeId(), sentOneWayIds)); | 194 | toDeviceRpcPendingMap.entrySet().stream().findFirst().ifPresent(processPendingRpc(context, sessionId, sessionInfo.getNodeId(), sentOneWayIds)); |
@@ -214,7 +203,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | @@ -214,7 +203,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | ||
214 | ToDeviceRpcRequestBody body = request.getBody(); | 203 | ToDeviceRpcRequestBody body = request.getBody(); |
215 | if (request.isOneway()) { | 204 | if (request.isOneway()) { |
216 | sentOneWayIds.add(entry.getKey()); | 205 | sentOneWayIds.add(entry.getKey()); |
217 | - systemContext.getDeviceRpcService().processResponseToServerSideRPCRequestFromDeviceActor(new FromDeviceRpcResponse(request.getId(), null, null)); | 206 | + systemContext.getTbCoreDeviceRpcService().processRpcResponseFromDeviceActor(new FromDeviceRpcResponse(request.getId(), null, null)); |
218 | } | 207 | } |
219 | ToDeviceRpcRequestMsg rpcRequest = ToDeviceRpcRequestMsg.newBuilder().setRequestId( | 208 | ToDeviceRpcRequestMsg rpcRequest = ToDeviceRpcRequestMsg.newBuilder().setRequestId( |
220 | entry.getKey()).setMethodName(body.getMethod()).setParams(body.getParams()).build(); | 209 | entry.getKey()).setMethodName(body.getMethod()).setParams(body.getParams()).build(); |
@@ -223,8 +212,8 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | @@ -223,8 +212,8 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | ||
223 | } | 212 | } |
224 | 213 | ||
225 | void process(ActorContext context, TransportToDeviceActorMsgWrapper wrapper) { | 214 | void process(ActorContext context, TransportToDeviceActorMsgWrapper wrapper) { |
226 | - boolean reportDeviceActivity = false; | ||
227 | TransportToDeviceActorMsg msg = wrapper.getMsg(); | 215 | TransportToDeviceActorMsg msg = wrapper.getMsg(); |
216 | + TbCallback callback = wrapper.getCallback(); | ||
228 | if (msg.hasSessionEvent()) { | 217 | if (msg.hasSessionEvent()) { |
229 | processSessionStateMsgs(msg.getSessionInfo(), msg.getSessionEvent()); | 218 | processSessionStateMsgs(msg.getSessionInfo(), msg.getSessionEvent()); |
230 | } | 219 | } |
@@ -234,34 +223,16 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | @@ -234,34 +223,16 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | ||
234 | if (msg.hasSubscribeToRPC()) { | 223 | if (msg.hasSubscribeToRPC()) { |
235 | processSubscriptionCommands(context, msg.getSessionInfo(), msg.getSubscribeToRPC()); | 224 | processSubscriptionCommands(context, msg.getSessionInfo(), msg.getSubscribeToRPC()); |
236 | } | 225 | } |
237 | - if (msg.hasPostAttributes()) { | ||
238 | - handlePostAttributesRequest(context, msg.getSessionInfo(), msg.getPostAttributes()); | ||
239 | - reportDeviceActivity = true; | ||
240 | - } | ||
241 | - if (msg.hasPostTelemetry()) { | ||
242 | - handlePostTelemetryRequest(context, msg.getSessionInfo(), msg.getPostTelemetry()); | ||
243 | - reportDeviceActivity = true; | ||
244 | - } | ||
245 | if (msg.hasGetAttributes()) { | 226 | if (msg.hasGetAttributes()) { |
246 | handleGetAttributesRequest(context, msg.getSessionInfo(), msg.getGetAttributes()); | 227 | handleGetAttributesRequest(context, msg.getSessionInfo(), msg.getGetAttributes()); |
247 | } | 228 | } |
248 | if (msg.hasToDeviceRPCCallResponse()) { | 229 | if (msg.hasToDeviceRPCCallResponse()) { |
249 | processRpcResponses(context, msg.getSessionInfo(), msg.getToDeviceRPCCallResponse()); | 230 | processRpcResponses(context, msg.getSessionInfo(), msg.getToDeviceRPCCallResponse()); |
250 | } | 231 | } |
251 | - if (msg.hasToServerRPCCallRequest()) { | ||
252 | - handleClientSideRPCRequest(context, msg.getSessionInfo(), msg.getToServerRPCCallRequest()); | ||
253 | - reportDeviceActivity = true; | ||
254 | - } | ||
255 | if (msg.hasSubscriptionInfo()) { | 232 | if (msg.hasSubscriptionInfo()) { |
256 | handleSessionActivity(context, msg.getSessionInfo(), msg.getSubscriptionInfo()); | 233 | handleSessionActivity(context, msg.getSessionInfo(), msg.getSubscriptionInfo()); |
257 | } | 234 | } |
258 | - if (reportDeviceActivity) { | ||
259 | - reportLogicalDeviceActivity(); | ||
260 | - } | ||
261 | - } | ||
262 | - | ||
263 | - private void reportLogicalDeviceActivity() { | ||
264 | - systemContext.getDeviceStateService().onDeviceActivity(deviceId); | 235 | + callback.onSuccess(); |
265 | } | 236 | } |
266 | 237 | ||
267 | private void reportSessionOpen() { | 238 | private void reportSessionOpen() { |
@@ -326,67 +297,8 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | @@ -326,67 +297,8 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | ||
326 | return new HashSet<>(strings); | 297 | return new HashSet<>(strings); |
327 | } | 298 | } |
328 | 299 | ||
329 | - private void handlePostAttributesRequest(ActorContext context, SessionInfoProto sessionInfo, PostAttributeMsg postAttributes) { | ||
330 | - JsonObject json = JsonUtils.getJsonObject(postAttributes.getKvList()); | ||
331 | - TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), SessionMsgType.POST_ATTRIBUTES_REQUEST.name(), deviceId, defaultMetaData.copy(), | ||
332 | - TbMsgDataType.JSON, gson.toJson(json), null, null, 0L); | ||
333 | - pushToRuleEngine(context, tbMsg); | ||
334 | - } | ||
335 | - | ||
336 | - private void handlePostTelemetryRequest(ActorContext context, SessionInfoProto sessionInfo, PostTelemetryMsg postTelemetry) { | ||
337 | - for (TsKvListProto tsKv : postTelemetry.getTsKvListList()) { | ||
338 | - JsonObject json = JsonUtils.getJsonObject(tsKv.getKvList()); | ||
339 | - TbMsgMetaData metaData = defaultMetaData.copy(); | ||
340 | - metaData.putValue("ts", tsKv.getTs() + ""); | ||
341 | - TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), SessionMsgType.POST_TELEMETRY_REQUEST.name(), deviceId, metaData, TbMsgDataType.JSON, gson.toJson(json), null, null, 0L); | ||
342 | - pushToRuleEngine(context, tbMsg); | ||
343 | - } | ||
344 | - } | ||
345 | - | ||
346 | - private void handleClientSideRPCRequest(ActorContext context, SessionInfoProto sessionInfo, TransportProtos.ToServerRpcRequestMsg request) { | ||
347 | - UUID sessionId = getSessionId(sessionInfo); | ||
348 | - JsonObject json = new JsonObject(); | ||
349 | - json.addProperty("method", request.getMethodName()); | ||
350 | - json.add("params", JsonUtils.parse(request.getParams())); | ||
351 | - | ||
352 | - TbMsgMetaData requestMetaData = defaultMetaData.copy(); | ||
353 | - requestMetaData.putValue("requestId", Integer.toString(request.getRequestId())); | ||
354 | - TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), SessionMsgType.TO_SERVER_RPC_REQUEST.name(), deviceId, requestMetaData, TbMsgDataType.JSON, gson.toJson(json), null, null, 0L); | ||
355 | - context.parent().tell(new DeviceActorToRuleEngineMsg(context.self(), tbMsg), context.self()); | ||
356 | - | ||
357 | - scheduleMsgWithDelay(context, new DeviceActorClientSideRpcTimeoutMsg(request.getRequestId(), systemContext.getClientSideRpcTimeout()), systemContext.getClientSideRpcTimeout()); | ||
358 | - toServerRpcPendingMap.put(request.getRequestId(), new ToServerRpcRequestMetadata(sessionId, getSessionType(sessionId), sessionInfo.getNodeId())); | ||
359 | - } | ||
360 | - | ||
361 | - private TransportProtos.SessionType getSessionType(UUID sessionId) { | ||
362 | - return sessions.containsKey(sessionId) ? TransportProtos.SessionType.ASYNC : TransportProtos.SessionType.SYNC; | ||
363 | - } | ||
364 | - | ||
365 | - void processClientSideRpcTimeout(ActorContext context, DeviceActorClientSideRpcTimeoutMsg msg) { | ||
366 | - ToServerRpcRequestMetadata data = toServerRpcPendingMap.remove(msg.getId()); | ||
367 | - if (data != null) { | ||
368 | - log.debug("[{}] Client side RPC request [{}] timeout detected!", deviceId, msg.getId()); | ||
369 | - sendToTransport(TransportProtos.ToServerRpcResponseMsg.newBuilder() | ||
370 | - .setRequestId(msg.getId()).setError("timeout").build() | ||
371 | - , data.getSessionId(), data.getNodeId()); | ||
372 | - } | ||
373 | - } | ||
374 | - | ||
375 | - void processToServerRPCResponse(ActorContext context, ToServerRpcResponseActorMsg msg) { | ||
376 | - int requestId = msg.getMsg().getRequestId(); | ||
377 | - ToServerRpcRequestMetadata data = toServerRpcPendingMap.remove(requestId); | ||
378 | - if (data != null) { | ||
379 | - log.debug("[{}] Pushing reply to [{}][{}]!", deviceId, data.getNodeId(), data.getSessionId()); | ||
380 | - sendToTransport(TransportProtos.ToServerRpcResponseMsg.newBuilder() | ||
381 | - .setRequestId(requestId).setPayload(msg.getMsg().getData()).build() | ||
382 | - , data.getSessionId(), data.getNodeId()); | ||
383 | - } else { | ||
384 | - log.debug("[{}][{}] Pending RPC request to server not found!", deviceId, requestId); | ||
385 | - } | ||
386 | - } | ||
387 | - | ||
388 | - private void pushToRuleEngine(ActorContext context, TbMsg tbMsg) { | ||
389 | - context.parent().tell(new DeviceActorToRuleEngineMsg(context.self(), tbMsg), context.self()); | 300 | + private SessionType getSessionType(UUID sessionId) { |
301 | + return sessions.containsKey(sessionId) ? SessionType.ASYNC : SessionType.SYNC; | ||
390 | } | 302 | } |
391 | 303 | ||
392 | void processAttributesUpdate(ActorContext context, DeviceAttributesEventNotificationMsg msg) { | 304 | void processAttributesUpdate(ActorContext context, DeviceAttributesEventNotificationMsg msg) { |
@@ -434,7 +346,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | @@ -434,7 +346,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | ||
434 | ToDeviceRpcRequestMetadata requestMd = toDeviceRpcPendingMap.remove(responseMsg.getRequestId()); | 346 | ToDeviceRpcRequestMetadata requestMd = toDeviceRpcPendingMap.remove(responseMsg.getRequestId()); |
435 | boolean success = requestMd != null; | 347 | boolean success = requestMd != null; |
436 | if (success) { | 348 | if (success) { |
437 | - systemContext.getDeviceRpcService().processResponseToServerSideRPCRequestFromDeviceActor(new FromDeviceRpcResponse(requestMd.getMsg().getMsg().getId(), | 349 | + systemContext.getTbCoreDeviceRpcService().processRpcResponseFromDeviceActor(new FromDeviceRpcResponse(requestMd.getMsg().getMsg().getId(), |
438 | responseMsg.getPayload(), null)); | 350 | responseMsg.getPayload(), null)); |
439 | } else { | 351 | } else { |
440 | log.debug("[{}] Rpc command response [{}] is stale!", deviceId, responseMsg.getRequestId()); | 352 | log.debug("[{}] Rpc command response [{}] is stale!", deviceId, responseMsg.getRequestId()); |
@@ -449,7 +361,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | @@ -449,7 +361,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | ||
449 | } else { | 361 | } else { |
450 | SessionInfoMetaData sessionMD = sessions.get(sessionId); | 362 | SessionInfoMetaData sessionMD = sessions.get(sessionId); |
451 | if (sessionMD == null) { | 363 | if (sessionMD == null) { |
452 | - sessionMD = new SessionInfoMetaData(new SessionInfo(TransportProtos.SessionType.SYNC, sessionInfo.getNodeId())); | 364 | + sessionMD = new SessionInfoMetaData(new SessionInfo(SessionType.SYNC, sessionInfo.getNodeId())); |
453 | } | 365 | } |
454 | sessionMD.setSubscribedToAttributes(true); | 366 | sessionMD.setSubscribedToAttributes(true); |
455 | log.debug("[{}] Registering attributes subscription for session [{}]", deviceId, sessionId); | 367 | log.debug("[{}] Registering attributes subscription for session [{}]", deviceId, sessionId); |
@@ -470,7 +382,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | @@ -470,7 +382,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | ||
470 | } else { | 382 | } else { |
471 | SessionInfoMetaData sessionMD = sessions.get(sessionId); | 383 | SessionInfoMetaData sessionMD = sessions.get(sessionId); |
472 | if (sessionMD == null) { | 384 | if (sessionMD == null) { |
473 | - sessionMD = new SessionInfoMetaData(new SessionInfo(TransportProtos.SessionType.SYNC, sessionInfo.getNodeId())); | 385 | + sessionMD = new SessionInfoMetaData(new SessionInfo(SessionType.SYNC, sessionInfo.getNodeId())); |
474 | } | 386 | } |
475 | sessionMD.setSubscribedToRPC(true); | 387 | sessionMD.setSubscribedToRPC(true); |
476 | log.debug("[{}] Registering rpc subscription for session [{}]", deviceId, sessionId); | 388 | log.debug("[{}] Registering rpc subscription for session [{}]", deviceId, sessionId); |
@@ -494,10 +406,11 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | @@ -494,10 +406,11 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | ||
494 | notifyTransportAboutClosedSession(sessionIdToRemove, sessions.remove(sessionIdToRemove)); | 406 | notifyTransportAboutClosedSession(sessionIdToRemove, sessions.remove(sessionIdToRemove)); |
495 | } | 407 | } |
496 | } | 408 | } |
497 | - sessions.put(sessionId, new SessionInfoMetaData(new SessionInfo(TransportProtos.SessionType.ASYNC, sessionInfo.getNodeId()))); | 409 | + sessions.put(sessionId, new SessionInfoMetaData(new SessionInfo(SessionType.ASYNC, sessionInfo.getNodeId()))); |
498 | if (sessions.size() == 1) { | 410 | if (sessions.size() == 1) { |
499 | reportSessionOpen(); | 411 | reportSessionOpen(); |
500 | } | 412 | } |
413 | + systemContext.getDeviceStateService().onDeviceActivity(deviceId, System.currentTimeMillis()); | ||
501 | dumpSessions(); | 414 | dumpSessions(); |
502 | } else if (msg.getEvent() == SessionEvent.CLOSED) { | 415 | } else if (msg.getEvent() == SessionEvent.CLOSED) { |
503 | log.debug("[{}] Canceling subscriptions for closed session [{}]", deviceId, sessionId); | 416 | log.debug("[{}] Canceling subscriptions for closed session [{}]", deviceId, sessionId); |
@@ -511,10 +424,10 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | @@ -511,10 +424,10 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | ||
511 | } | 424 | } |
512 | } | 425 | } |
513 | 426 | ||
514 | - private void handleSessionActivity(ActorContext context, SessionInfoProto sessionInfoProto, TransportProtos.SubscriptionInfoProto subscriptionInfo) { | 427 | + private void handleSessionActivity(ActorContext context, SessionInfoProto sessionInfoProto, SubscriptionInfoProto subscriptionInfo) { |
515 | UUID sessionId = getSessionId(sessionInfoProto); | 428 | UUID sessionId = getSessionId(sessionInfoProto); |
516 | SessionInfoMetaData sessionMD = sessions.computeIfAbsent(sessionId, | 429 | SessionInfoMetaData sessionMD = sessions.computeIfAbsent(sessionId, |
517 | - id -> new SessionInfoMetaData(new SessionInfo(TransportProtos.SessionType.ASYNC, sessionInfoProto.getNodeId()), 0L)); | 430 | + id -> new SessionInfoMetaData(new SessionInfo(SessionType.ASYNC, sessionInfoProto.getNodeId()), 0L)); |
518 | 431 | ||
519 | sessionMD.setLastActivityTime(subscriptionInfo.getLastActivityTime()); | 432 | sessionMD.setLastActivityTime(subscriptionInfo.getLastActivityTime()); |
520 | sessionMD.setSubscribedToAttributes(subscriptionInfo.getAttributeSubscription()); | 433 | sessionMD.setSubscribedToAttributes(subscriptionInfo.getAttributeSubscription()); |
@@ -525,6 +438,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | @@ -525,6 +438,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | ||
525 | if (subscriptionInfo.getRpcSubscription()) { | 438 | if (subscriptionInfo.getRpcSubscription()) { |
526 | rpcSubscriptions.putIfAbsent(sessionId, sessionMD.getSessionInfo()); | 439 | rpcSubscriptions.putIfAbsent(sessionId, sessionMD.getSessionInfo()); |
527 | } | 440 | } |
441 | + systemContext.getDeviceStateService().onDeviceActivity(deviceId, subscriptionInfo.getLastActivityTime()); | ||
528 | dumpSessions(); | 442 | dumpSessions(); |
529 | } | 443 | } |
530 | 444 | ||
@@ -536,11 +450,11 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | @@ -536,11 +450,11 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | ||
536 | } | 450 | } |
537 | 451 | ||
538 | private void notifyTransportAboutClosedSession(UUID sessionId, SessionInfoMetaData sessionMd) { | 452 | private void notifyTransportAboutClosedSession(UUID sessionId, SessionInfoMetaData sessionMd) { |
539 | - DeviceActorToTransportMsg msg = DeviceActorToTransportMsg.newBuilder() | 453 | + ToTransportMsg msg = ToTransportMsg.newBuilder() |
540 | .setSessionIdMSB(sessionId.getMostSignificantBits()) | 454 | .setSessionIdMSB(sessionId.getMostSignificantBits()) |
541 | .setSessionIdLSB(sessionId.getLeastSignificantBits()) | 455 | .setSessionIdLSB(sessionId.getLeastSignificantBits()) |
542 | .setSessionCloseNotification(SessionCloseNotificationProto.getDefaultInstance()).build(); | 456 | .setSessionCloseNotification(SessionCloseNotificationProto.getDefaultInstance()).build(); |
543 | - systemContext.getRuleEngineTransportService().process(sessionMd.getSessionInfo().getNodeId(), msg); | 457 | + systemContext.getTbCoreToTransportService().process(sessionMd.getSessionInfo().getNodeId(), msg); |
544 | } | 458 | } |
545 | 459 | ||
546 | void processNameOrTypeUpdate(DeviceNameOrTypeUpdateMsg msg) { | 460 | void processNameOrTypeUpdate(DeviceNameOrTypeUpdateMsg msg) { |
@@ -552,35 +466,35 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | @@ -552,35 +466,35 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | ||
552 | } | 466 | } |
553 | 467 | ||
554 | private void sendToTransport(GetAttributeResponseMsg responseMsg, SessionInfoProto sessionInfo) { | 468 | private void sendToTransport(GetAttributeResponseMsg responseMsg, SessionInfoProto sessionInfo) { |
555 | - DeviceActorToTransportMsg msg = DeviceActorToTransportMsg.newBuilder() | 469 | + ToTransportMsg msg = ToTransportMsg.newBuilder() |
556 | .setSessionIdMSB(sessionInfo.getSessionIdMSB()) | 470 | .setSessionIdMSB(sessionInfo.getSessionIdMSB()) |
557 | .setSessionIdLSB(sessionInfo.getSessionIdLSB()) | 471 | .setSessionIdLSB(sessionInfo.getSessionIdLSB()) |
558 | .setGetAttributesResponse(responseMsg).build(); | 472 | .setGetAttributesResponse(responseMsg).build(); |
559 | - systemContext.getRuleEngineTransportService().process(sessionInfo.getNodeId(), msg); | 473 | + systemContext.getTbCoreToTransportService().process(sessionInfo.getNodeId(), msg); |
560 | } | 474 | } |
561 | 475 | ||
562 | private void sendToTransport(AttributeUpdateNotificationMsg notificationMsg, UUID sessionId, String nodeId) { | 476 | private void sendToTransport(AttributeUpdateNotificationMsg notificationMsg, UUID sessionId, String nodeId) { |
563 | - DeviceActorToTransportMsg msg = DeviceActorToTransportMsg.newBuilder() | 477 | + ToTransportMsg msg = ToTransportMsg.newBuilder() |
564 | .setSessionIdMSB(sessionId.getMostSignificantBits()) | 478 | .setSessionIdMSB(sessionId.getMostSignificantBits()) |
565 | .setSessionIdLSB(sessionId.getLeastSignificantBits()) | 479 | .setSessionIdLSB(sessionId.getLeastSignificantBits()) |
566 | .setAttributeUpdateNotification(notificationMsg).build(); | 480 | .setAttributeUpdateNotification(notificationMsg).build(); |
567 | - systemContext.getRuleEngineTransportService().process(nodeId, msg); | 481 | + systemContext.getTbCoreToTransportService().process(nodeId, msg); |
568 | } | 482 | } |
569 | 483 | ||
570 | private void sendToTransport(ToDeviceRpcRequestMsg rpcMsg, UUID sessionId, String nodeId) { | 484 | private void sendToTransport(ToDeviceRpcRequestMsg rpcMsg, UUID sessionId, String nodeId) { |
571 | - DeviceActorToTransportMsg msg = DeviceActorToTransportMsg.newBuilder() | 485 | + ToTransportMsg msg = ToTransportMsg.newBuilder() |
572 | .setSessionIdMSB(sessionId.getMostSignificantBits()) | 486 | .setSessionIdMSB(sessionId.getMostSignificantBits()) |
573 | .setSessionIdLSB(sessionId.getLeastSignificantBits()) | 487 | .setSessionIdLSB(sessionId.getLeastSignificantBits()) |
574 | .setToDeviceRequest(rpcMsg).build(); | 488 | .setToDeviceRequest(rpcMsg).build(); |
575 | - systemContext.getRuleEngineTransportService().process(nodeId, msg); | 489 | + systemContext.getTbCoreToTransportService().process(nodeId, msg); |
576 | } | 490 | } |
577 | 491 | ||
578 | - private void sendToTransport(TransportProtos.ToServerRpcResponseMsg rpcMsg, UUID sessionId, String nodeId) { | ||
579 | - DeviceActorToTransportMsg msg = DeviceActorToTransportMsg.newBuilder() | 492 | + private void sendToTransport(ToServerRpcResponseMsg rpcMsg, UUID sessionId, String nodeId) { |
493 | + ToTransportMsg msg = ToTransportMsg.newBuilder() | ||
580 | .setSessionIdMSB(sessionId.getMostSignificantBits()) | 494 | .setSessionIdMSB(sessionId.getMostSignificantBits()) |
581 | .setSessionIdLSB(sessionId.getLeastSignificantBits()) | 495 | .setSessionIdLSB(sessionId.getLeastSignificantBits()) |
582 | .setToServerResponse(rpcMsg).build(); | 496 | .setToServerResponse(rpcMsg).build(); |
583 | - systemContext.getRuleEngineTransportService().process(nodeId, msg); | 497 | + systemContext.getTbCoreToTransportService().process(nodeId, msg); |
584 | } | 498 | } |
585 | 499 | ||
586 | 500 | ||
@@ -632,9 +546,9 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | @@ -632,9 +546,9 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | ||
632 | 546 | ||
633 | private void restoreSessions() { | 547 | private void restoreSessions() { |
634 | log.debug("[{}] Restoring sessions from cache", deviceId); | 548 | log.debug("[{}] Restoring sessions from cache", deviceId); |
635 | - TransportProtos.DeviceSessionsCacheEntry sessionsDump = null; | 549 | + DeviceSessionsCacheEntry sessionsDump = null; |
636 | try { | 550 | try { |
637 | - sessionsDump = TransportProtos.DeviceSessionsCacheEntry.parseFrom(systemContext.getDeviceSessionCacheService().get(deviceId)); | 551 | + sessionsDump = DeviceSessionsCacheEntry.parseFrom(systemContext.getDeviceSessionCacheService().get(deviceId)); |
638 | } catch (InvalidProtocolBufferException e) { | 552 | } catch (InvalidProtocolBufferException e) { |
639 | log.warn("[{}] Failed to decode device sessions from cache", deviceId); | 553 | log.warn("[{}] Failed to decode device sessions from cache", deviceId); |
640 | return; | 554 | return; |
@@ -643,11 +557,11 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | @@ -643,11 +557,11 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | ||
643 | log.debug("[{}] No session information found", deviceId); | 557 | log.debug("[{}] No session information found", deviceId); |
644 | return; | 558 | return; |
645 | } | 559 | } |
646 | - for (TransportProtos.SessionSubscriptionInfoProto sessionSubscriptionInfoProto : sessionsDump.getSessionsList()) { | 560 | + for (SessionSubscriptionInfoProto sessionSubscriptionInfoProto : sessionsDump.getSessionsList()) { |
647 | SessionInfoProto sessionInfoProto = sessionSubscriptionInfoProto.getSessionInfo(); | 561 | SessionInfoProto sessionInfoProto = sessionSubscriptionInfoProto.getSessionInfo(); |
648 | UUID sessionId = getSessionId(sessionInfoProto); | 562 | UUID sessionId = getSessionId(sessionInfoProto); |
649 | - SessionInfo sessionInfo = new SessionInfo(TransportProtos.SessionType.ASYNC, sessionInfoProto.getNodeId()); | ||
650 | - TransportProtos.SubscriptionInfoProto subInfo = sessionSubscriptionInfoProto.getSubscriptionInfo(); | 563 | + SessionInfo sessionInfo = new SessionInfo(SessionType.ASYNC, sessionInfoProto.getNodeId()); |
564 | + SubscriptionInfoProto subInfo = sessionSubscriptionInfoProto.getSubscriptionInfo(); | ||
651 | SessionInfoMetaData sessionMD = new SessionInfoMetaData(sessionInfo, subInfo.getLastActivityTime()); | 565 | SessionInfoMetaData sessionMD = new SessionInfoMetaData(sessionInfo, subInfo.getLastActivityTime()); |
652 | sessions.put(sessionId, sessionMD); | 566 | sessions.put(sessionId, sessionMD); |
653 | if (subInfo.getAttributeSubscription()) { | 567 | if (subInfo.getAttributeSubscription()) { |
@@ -665,27 +579,27 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | @@ -665,27 +579,27 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | ||
665 | 579 | ||
666 | private void dumpSessions() { | 580 | private void dumpSessions() { |
667 | log.debug("[{}] Dumping sessions: {}, rpc subscriptions: {}, attribute subscriptions: {} to cache", deviceId, sessions.size(), rpcSubscriptions.size(), attributeSubscriptions.size()); | 581 | log.debug("[{}] Dumping sessions: {}, rpc subscriptions: {}, attribute subscriptions: {} to cache", deviceId, sessions.size(), rpcSubscriptions.size(), attributeSubscriptions.size()); |
668 | - List<TransportProtos.SessionSubscriptionInfoProto> sessionsList = new ArrayList<>(sessions.size()); | 582 | + List<SessionSubscriptionInfoProto> sessionsList = new ArrayList<>(sessions.size()); |
669 | sessions.forEach((uuid, sessionMD) -> { | 583 | sessions.forEach((uuid, sessionMD) -> { |
670 | - if (sessionMD.getSessionInfo().getType() == TransportProtos.SessionType.SYNC) { | 584 | + if (sessionMD.getSessionInfo().getType() == SessionType.SYNC) { |
671 | return; | 585 | return; |
672 | } | 586 | } |
673 | SessionInfo sessionInfo = sessionMD.getSessionInfo(); | 587 | SessionInfo sessionInfo = sessionMD.getSessionInfo(); |
674 | - TransportProtos.SubscriptionInfoProto subscriptionInfoProto = TransportProtos.SubscriptionInfoProto.newBuilder() | 588 | + SubscriptionInfoProto subscriptionInfoProto = SubscriptionInfoProto.newBuilder() |
675 | .setLastActivityTime(sessionMD.getLastActivityTime()) | 589 | .setLastActivityTime(sessionMD.getLastActivityTime()) |
676 | .setAttributeSubscription(sessionMD.isSubscribedToAttributes()) | 590 | .setAttributeSubscription(sessionMD.isSubscribedToAttributes()) |
677 | .setRpcSubscription(sessionMD.isSubscribedToRPC()).build(); | 591 | .setRpcSubscription(sessionMD.isSubscribedToRPC()).build(); |
678 | - TransportProtos.SessionInfoProto sessionInfoProto = TransportProtos.SessionInfoProto.newBuilder() | 592 | + SessionInfoProto sessionInfoProto = SessionInfoProto.newBuilder() |
679 | .setSessionIdMSB(uuid.getMostSignificantBits()) | 593 | .setSessionIdMSB(uuid.getMostSignificantBits()) |
680 | .setSessionIdLSB(uuid.getLeastSignificantBits()) | 594 | .setSessionIdLSB(uuid.getLeastSignificantBits()) |
681 | .setNodeId(sessionInfo.getNodeId()).build(); | 595 | .setNodeId(sessionInfo.getNodeId()).build(); |
682 | - sessionsList.add(TransportProtos.SessionSubscriptionInfoProto.newBuilder() | 596 | + sessionsList.add(SessionSubscriptionInfoProto.newBuilder() |
683 | .setSessionInfo(sessionInfoProto) | 597 | .setSessionInfo(sessionInfoProto) |
684 | .setSubscriptionInfo(subscriptionInfoProto).build()); | 598 | .setSubscriptionInfo(subscriptionInfoProto).build()); |
685 | log.debug("[{}] Dumping session: {}", deviceId, sessionMD); | 599 | log.debug("[{}] Dumping session: {}", deviceId, sessionMD); |
686 | }); | 600 | }); |
687 | systemContext.getDeviceSessionCacheService() | 601 | systemContext.getDeviceSessionCacheService() |
688 | - .put(deviceId, TransportProtos.DeviceSessionsCacheEntry.newBuilder() | 602 | + .put(deviceId, DeviceSessionsCacheEntry.newBuilder() |
689 | .addAllSessions(sessionsList).build().toByteArray()); | 603 | .addAllSessions(sessionsList).build().toByteArray()); |
690 | } | 604 | } |
691 | 605 | ||
@@ -706,4 +620,5 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | @@ -706,4 +620,5 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | ||
706 | dumpSessions(); | 620 | dumpSessions(); |
707 | } | 621 | } |
708 | } | 622 | } |
623 | + | ||
709 | } | 624 | } |
application/src/main/java/org/thingsboard/server/actors/rpc/BasicRpcSessionListener.java
deleted
100644 → 0
1 | -/** | ||
2 | - * Copyright © 2016-2020 The Thingsboard Authors | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.thingsboard.server.actors.rpc; | ||
17 | - | ||
18 | -import akka.actor.ActorRef; | ||
19 | -import lombok.extern.slf4j.Slf4j; | ||
20 | -import org.thingsboard.server.actors.ActorSystemContext; | ||
21 | -import org.thingsboard.server.actors.service.ActorService; | ||
22 | -import org.thingsboard.server.gen.cluster.ClusterAPIProtos; | ||
23 | -import org.thingsboard.server.service.cluster.rpc.GrpcSession; | ||
24 | -import org.thingsboard.server.service.cluster.rpc.GrpcSessionListener; | ||
25 | -import org.thingsboard.server.service.executors.ClusterRpcCallbackExecutorService; | ||
26 | - | ||
27 | -/** | ||
28 | - * @author Andrew Shvayka | ||
29 | - */ | ||
30 | -@Slf4j | ||
31 | -public class BasicRpcSessionListener implements GrpcSessionListener { | ||
32 | - | ||
33 | - private final ClusterRpcCallbackExecutorService callbackExecutorService; | ||
34 | - private final ActorService service; | ||
35 | - private final ActorRef manager; | ||
36 | - private final ActorRef self; | ||
37 | - | ||
38 | - BasicRpcSessionListener(ActorSystemContext context, ActorRef manager, ActorRef self) { | ||
39 | - this.service = context.getActorService(); | ||
40 | - this.callbackExecutorService = context.getClusterRpcCallbackExecutor(); | ||
41 | - this.manager = manager; | ||
42 | - this.self = self; | ||
43 | - } | ||
44 | - | ||
45 | - @Override | ||
46 | - public void onConnected(GrpcSession session) { | ||
47 | - log.info("[{}][{}] session started", session.getRemoteServer(), getType(session)); | ||
48 | - if (!session.isClient()) { | ||
49 | - manager.tell(new RpcSessionConnectedMsg(session.getRemoteServer(), session.getSessionId()), self); | ||
50 | - } | ||
51 | - } | ||
52 | - | ||
53 | - @Override | ||
54 | - public void onDisconnected(GrpcSession session) { | ||
55 | - log.info("[{}][{}] session closed", session.getRemoteServer(), getType(session)); | ||
56 | - manager.tell(new RpcSessionDisconnectedMsg(session.isClient(), session.getRemoteServer()), self); | ||
57 | - } | ||
58 | - | ||
59 | - @Override | ||
60 | - public void onReceiveClusterGrpcMsg(GrpcSession session, ClusterAPIProtos.ClusterMessage clusterMessage) { | ||
61 | - log.trace("Received session actor msg from [{}][{}]: {}", session.getRemoteServer(), getType(session), clusterMessage); | ||
62 | - callbackExecutorService.execute(() -> { | ||
63 | - try { | ||
64 | - service.onReceivedMsg(session.getRemoteServer(), clusterMessage); | ||
65 | - } catch (Exception e) { | ||
66 | - log.debug("[{}][{}] Failed to process cluster message: {}", session.getRemoteServer(), getType(session), clusterMessage, e); | ||
67 | - } | ||
68 | - }); | ||
69 | - } | ||
70 | - | ||
71 | - @Override | ||
72 | - public void onError(GrpcSession session, Throwable t) { | ||
73 | - log.warn("[{}][{}] session got error -> {}", session.getRemoteServer(), getType(session), t); | ||
74 | - manager.tell(new RpcSessionClosedMsg(session.isClient(), session.getRemoteServer()), self); | ||
75 | - session.close(); | ||
76 | - } | ||
77 | - | ||
78 | - private static String getType(GrpcSession session) { | ||
79 | - return session.isClient() ? "Client" : "Server"; | ||
80 | - } | ||
81 | - | ||
82 | - | ||
83 | -} |
1 | -/** | ||
2 | - * Copyright © 2016-2020 The Thingsboard Authors | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.thingsboard.server.actors.rpc; | ||
17 | - | ||
18 | -import akka.actor.ActorRef; | ||
19 | -import akka.actor.OneForOneStrategy; | ||
20 | -import akka.actor.Props; | ||
21 | -import akka.actor.SupervisorStrategy; | ||
22 | -import akka.event.Logging; | ||
23 | -import akka.event.LoggingAdapter; | ||
24 | -import lombok.extern.slf4j.Slf4j; | ||
25 | -import org.thingsboard.server.actors.ActorSystemContext; | ||
26 | -import org.thingsboard.server.actors.service.ContextAwareActor; | ||
27 | -import org.thingsboard.server.actors.service.ContextBasedCreator; | ||
28 | -import org.thingsboard.server.actors.service.DefaultActorService; | ||
29 | -import org.thingsboard.server.common.msg.TbActorMsg; | ||
30 | -import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; | ||
31 | -import org.thingsboard.server.common.msg.cluster.ServerAddress; | ||
32 | -import org.thingsboard.server.common.msg.cluster.ServerType; | ||
33 | -import org.thingsboard.server.gen.cluster.ClusterAPIProtos; | ||
34 | -import org.thingsboard.server.service.cluster.discovery.ServerInstance; | ||
35 | -import scala.concurrent.duration.Duration; | ||
36 | - | ||
37 | -import java.util.*; | ||
38 | - | ||
39 | -/** | ||
40 | - * @author Andrew Shvayka | ||
41 | - */ | ||
42 | -public class RpcManagerActor extends ContextAwareActor { | ||
43 | - | ||
44 | - private final Map<ServerAddress, SessionActorInfo> sessionActors; | ||
45 | - private final Map<ServerAddress, Queue<ClusterAPIProtos.ClusterMessage>> pendingMsgs; | ||
46 | - private final ServerAddress instance; | ||
47 | - | ||
48 | - private RpcManagerActor(ActorSystemContext systemContext) { | ||
49 | - super(systemContext); | ||
50 | - this.sessionActors = new HashMap<>(); | ||
51 | - this.pendingMsgs = new HashMap<>(); | ||
52 | - this.instance = systemContext.getDiscoveryService().getCurrentServer().getServerAddress(); | ||
53 | - | ||
54 | - systemContext.getDiscoveryService().getOtherServers().stream() | ||
55 | - .filter(otherServer -> otherServer.getServerAddress().compareTo(instance) > 0) | ||
56 | - .forEach(otherServer -> onCreateSessionRequest( | ||
57 | - new RpcSessionCreateRequestMsg(UUID.randomUUID(), otherServer.getServerAddress(), null))); | ||
58 | - } | ||
59 | - | ||
60 | - @Override | ||
61 | - protected boolean process(TbActorMsg msg) { | ||
62 | - //TODO Move everything here, to work with TbActorMsg | ||
63 | - return false; | ||
64 | - } | ||
65 | - | ||
66 | - @Override | ||
67 | - public void onReceive(Object msg) { | ||
68 | - if (msg instanceof ClusterAPIProtos.ClusterMessage) { | ||
69 | - onMsg((ClusterAPIProtos.ClusterMessage) msg); | ||
70 | - } else if (msg instanceof RpcBroadcastMsg) { | ||
71 | - onMsg((RpcBroadcastMsg) msg); | ||
72 | - } else if (msg instanceof RpcSessionCreateRequestMsg) { | ||
73 | - onCreateSessionRequest((RpcSessionCreateRequestMsg) msg); | ||
74 | - } else if (msg instanceof RpcSessionConnectedMsg) { | ||
75 | - onSessionConnected((RpcSessionConnectedMsg) msg); | ||
76 | - } else if (msg instanceof RpcSessionDisconnectedMsg) { | ||
77 | - onSessionDisconnected((RpcSessionDisconnectedMsg) msg); | ||
78 | - } else if (msg instanceof RpcSessionClosedMsg) { | ||
79 | - onSessionClosed((RpcSessionClosedMsg) msg); | ||
80 | - } else if (msg instanceof ClusterEventMsg) { | ||
81 | - onClusterEvent((ClusterEventMsg) msg); | ||
82 | - } | ||
83 | - } | ||
84 | - | ||
85 | - private void onMsg(RpcBroadcastMsg msg) { | ||
86 | - log.debug("Forwarding msg to session actors {}", msg); | ||
87 | - sessionActors.keySet().forEach(address -> { | ||
88 | - ClusterAPIProtos.ClusterMessage msgWithServerAddress = msg.getMsg() | ||
89 | - .toBuilder() | ||
90 | - .setServerAddress(ClusterAPIProtos.ServerAddress | ||
91 | - .newBuilder() | ||
92 | - .setHost(address.getHost()) | ||
93 | - .setPort(address.getPort()) | ||
94 | - .build()) | ||
95 | - .build(); | ||
96 | - onMsg(msgWithServerAddress); | ||
97 | - }); | ||
98 | - pendingMsgs.values().forEach(queue -> queue.add(msg.getMsg())); | ||
99 | - } | ||
100 | - | ||
101 | - private void onMsg(ClusterAPIProtos.ClusterMessage msg) { | ||
102 | - if (msg.hasServerAddress()) { | ||
103 | - ServerAddress address = new ServerAddress(msg.getServerAddress().getHost(), msg.getServerAddress().getPort(), ServerType.CORE); | ||
104 | - SessionActorInfo session = sessionActors.get(address); | ||
105 | - if (session != null) { | ||
106 | - log.debug("{} Forwarding msg to session actor: {}", address, msg); | ||
107 | - session.getActor().tell(msg, ActorRef.noSender()); | ||
108 | - } else { | ||
109 | - log.debug("{} Storing msg to pending queue: {}", address, msg); | ||
110 | - Queue<ClusterAPIProtos.ClusterMessage> queue = pendingMsgs.get(address); | ||
111 | - if (queue == null) { | ||
112 | - queue = new LinkedList<>(); | ||
113 | - pendingMsgs.put(new ServerAddress( | ||
114 | - msg.getServerAddress().getHost(), msg.getServerAddress().getPort(), ServerType.CORE), queue); | ||
115 | - } | ||
116 | - queue.add(msg); | ||
117 | - } | ||
118 | - } else { | ||
119 | - log.warn("Cluster msg doesn't have server address [{}]", msg); | ||
120 | - } | ||
121 | - } | ||
122 | - | ||
123 | - @Override | ||
124 | - public void postStop() { | ||
125 | - sessionActors.clear(); | ||
126 | - pendingMsgs.clear(); | ||
127 | - } | ||
128 | - | ||
129 | - private void onClusterEvent(ClusterEventMsg msg) { | ||
130 | - ServerAddress server = msg.getServerAddress(); | ||
131 | - if (server.compareTo(instance) > 0) { | ||
132 | - if (msg.isAdded()) { | ||
133 | - onCreateSessionRequest(new RpcSessionCreateRequestMsg(UUID.randomUUID(), server, null)); | ||
134 | - } else { | ||
135 | - onSessionClose(false, server); | ||
136 | - } | ||
137 | - } | ||
138 | - } | ||
139 | - | ||
140 | - private void onSessionConnected(RpcSessionConnectedMsg msg) { | ||
141 | - register(msg.getRemoteAddress(), msg.getId(), context().sender()); | ||
142 | - } | ||
143 | - | ||
144 | - private void onSessionDisconnected(RpcSessionDisconnectedMsg msg) { | ||
145 | - boolean reconnect = msg.isClient() && isRegistered(msg.getRemoteAddress()); | ||
146 | - onSessionClose(reconnect, msg.getRemoteAddress()); | ||
147 | - } | ||
148 | - | ||
149 | - private void onSessionClosed(RpcSessionClosedMsg msg) { | ||
150 | - boolean reconnect = msg.isClient() && isRegistered(msg.getRemoteAddress()); | ||
151 | - onSessionClose(reconnect, msg.getRemoteAddress()); | ||
152 | - } | ||
153 | - | ||
154 | - private boolean isRegistered(ServerAddress address) { | ||
155 | - for (ServerInstance server : systemContext.getDiscoveryService().getOtherServers()) { | ||
156 | - if (server.getServerAddress().equals(address)) { | ||
157 | - return true; | ||
158 | - } | ||
159 | - } | ||
160 | - return false; | ||
161 | - } | ||
162 | - | ||
163 | - private void onSessionClose(boolean reconnect, ServerAddress remoteAddress) { | ||
164 | - log.info("[{}] session closed. Should reconnect: {}", remoteAddress, reconnect); | ||
165 | - SessionActorInfo sessionRef = sessionActors.get(remoteAddress); | ||
166 | - if (sessionRef != null && context().sender() != null && context().sender().equals(sessionRef.actor)) { | ||
167 | - context().stop(sessionRef.actor); | ||
168 | - sessionActors.remove(remoteAddress); | ||
169 | - pendingMsgs.remove(remoteAddress); | ||
170 | - if (reconnect) { | ||
171 | - onCreateSessionRequest(new RpcSessionCreateRequestMsg(sessionRef.sessionId, remoteAddress, null)); | ||
172 | - } | ||
173 | - } | ||
174 | - } | ||
175 | - | ||
176 | - private void onCreateSessionRequest(RpcSessionCreateRequestMsg msg) { | ||
177 | - if (msg.getRemoteAddress() != null) { | ||
178 | - if (!sessionActors.containsKey(msg.getRemoteAddress())) { | ||
179 | - ActorRef actorRef = createSessionActor(msg); | ||
180 | - register(msg.getRemoteAddress(), msg.getMsgUid(), actorRef); | ||
181 | - } | ||
182 | - } else { | ||
183 | - createSessionActor(msg); | ||
184 | - } | ||
185 | - } | ||
186 | - | ||
187 | - private void register(ServerAddress remoteAddress, UUID uuid, ActorRef sender) { | ||
188 | - sessionActors.put(remoteAddress, new SessionActorInfo(uuid, sender)); | ||
189 | - log.info("[{}][{}] Registering session actor.", remoteAddress, uuid); | ||
190 | - Queue<ClusterAPIProtos.ClusterMessage> data = pendingMsgs.remove(remoteAddress); | ||
191 | - if (data != null) { | ||
192 | - log.info("[{}][{}] Forwarding {} pending messages.", remoteAddress, uuid, data.size()); | ||
193 | - data.forEach(msg -> sender.tell(new RpcSessionTellMsg(msg), ActorRef.noSender())); | ||
194 | - } else { | ||
195 | - log.info("[{}][{}] No pending messages to forward.", remoteAddress, uuid); | ||
196 | - } | ||
197 | - } | ||
198 | - | ||
199 | - private ActorRef createSessionActor(RpcSessionCreateRequestMsg msg) { | ||
200 | - log.info("[{}] Creating session actor.", msg.getMsgUid()); | ||
201 | - ActorRef actor = context().actorOf( | ||
202 | - Props.create(new RpcSessionActor.ActorCreator(systemContext, msg.getMsgUid())) | ||
203 | - .withDispatcher(DefaultActorService.RPC_DISPATCHER_NAME)); | ||
204 | - actor.tell(msg, context().self()); | ||
205 | - return actor; | ||
206 | - } | ||
207 | - | ||
208 | - public static class ActorCreator extends ContextBasedCreator<RpcManagerActor> { | ||
209 | - private static final long serialVersionUID = 1L; | ||
210 | - | ||
211 | - public ActorCreator(ActorSystemContext context) { | ||
212 | - super(context); | ||
213 | - } | ||
214 | - | ||
215 | - @Override | ||
216 | - public RpcManagerActor create() { | ||
217 | - return new RpcManagerActor(context); | ||
218 | - } | ||
219 | - } | ||
220 | - | ||
221 | - @Override | ||
222 | - public SupervisorStrategy supervisorStrategy() { | ||
223 | - return strategy; | ||
224 | - } | ||
225 | - | ||
226 | - private final SupervisorStrategy strategy = new OneForOneStrategy(3, Duration.create("1 minute"), t -> { | ||
227 | - log.warn("Unknown failure", t); | ||
228 | - return SupervisorStrategy.resume(); | ||
229 | - }); | ||
230 | -} |
1 | -/** | ||
2 | - * Copyright © 2016-2020 The Thingsboard Authors | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.thingsboard.server.actors.rpc; | ||
17 | - | ||
18 | -import io.grpc.ManagedChannel; | ||
19 | -import io.grpc.ManagedChannelBuilder; | ||
20 | -import io.grpc.stub.StreamObserver; | ||
21 | -import lombok.extern.slf4j.Slf4j; | ||
22 | -import org.thingsboard.server.actors.ActorSystemContext; | ||
23 | -import org.thingsboard.server.actors.service.ContextAwareActor; | ||
24 | -import org.thingsboard.server.actors.service.ContextBasedCreator; | ||
25 | -import org.thingsboard.server.common.msg.TbActorMsg; | ||
26 | -import org.thingsboard.server.common.msg.cluster.ServerAddress; | ||
27 | -import org.thingsboard.server.gen.cluster.ClusterAPIProtos; | ||
28 | -import org.thingsboard.server.gen.cluster.ClusterRpcServiceGrpc; | ||
29 | -import org.thingsboard.server.service.cluster.rpc.GrpcSession; | ||
30 | -import org.thingsboard.server.service.cluster.rpc.GrpcSessionListener; | ||
31 | - | ||
32 | -import java.util.UUID; | ||
33 | - | ||
34 | -import static org.thingsboard.server.gen.cluster.ClusterAPIProtos.MessageType.CONNECT_RPC_MESSAGE; | ||
35 | - | ||
36 | -/** | ||
37 | - * @author Andrew Shvayka | ||
38 | - */ | ||
39 | -@Slf4j | ||
40 | -public class RpcSessionActor extends ContextAwareActor { | ||
41 | - | ||
42 | - | ||
43 | - private final UUID sessionId; | ||
44 | - private GrpcSession session; | ||
45 | - private GrpcSessionListener listener; | ||
46 | - | ||
47 | - private RpcSessionActor(ActorSystemContext systemContext, UUID sessionId) { | ||
48 | - super(systemContext); | ||
49 | - this.sessionId = sessionId; | ||
50 | - } | ||
51 | - | ||
52 | - @Override | ||
53 | - protected boolean process(TbActorMsg msg) { | ||
54 | - //TODO Move everything here, to work with TbActorMsg | ||
55 | - return false; | ||
56 | - } | ||
57 | - | ||
58 | - @Override | ||
59 | - public void onReceive(Object msg) { | ||
60 | - if (msg instanceof ClusterAPIProtos.ClusterMessage) { | ||
61 | - tell((ClusterAPIProtos.ClusterMessage) msg); | ||
62 | - } else if (msg instanceof RpcSessionCreateRequestMsg) { | ||
63 | - initSession((RpcSessionCreateRequestMsg) msg); | ||
64 | - } | ||
65 | - } | ||
66 | - | ||
67 | - private void tell(ClusterAPIProtos.ClusterMessage msg) { | ||
68 | - if (session != null) { | ||
69 | - session.sendMsg(msg); | ||
70 | - } else { | ||
71 | - log.trace("Failed to send message due to missing session!"); | ||
72 | - } | ||
73 | - } | ||
74 | - | ||
75 | - @Override | ||
76 | - public void postStop() { | ||
77 | - if (session != null) { | ||
78 | - log.info("Closing session -> {}", session.getRemoteServer()); | ||
79 | - try { | ||
80 | - session.close(); | ||
81 | - } catch (RuntimeException e) { | ||
82 | - log.trace("Failed to close session!", e); | ||
83 | - } | ||
84 | - } | ||
85 | - } | ||
86 | - | ||
87 | - private void initSession(RpcSessionCreateRequestMsg msg) { | ||
88 | - log.info("[{}] Initializing session", context().self()); | ||
89 | - ServerAddress remoteServer = msg.getRemoteAddress(); | ||
90 | - listener = new BasicRpcSessionListener(systemContext, context().parent(), context().self()); | ||
91 | - if (msg.getRemoteAddress() == null) { | ||
92 | - // Server session | ||
93 | - session = new GrpcSession(listener); | ||
94 | - session.setOutputStream(msg.getResponseObserver()); | ||
95 | - session.initInputStream(); | ||
96 | - session.initOutputStream(); | ||
97 | - systemContext.getRpcService().onSessionCreated(msg.getMsgUid(), session.getInputStream()); | ||
98 | - } else { | ||
99 | - // Client session | ||
100 | - ManagedChannel channel = ManagedChannelBuilder.forAddress(remoteServer.getHost(), remoteServer.getPort()).usePlaintext().build(); | ||
101 | - session = new GrpcSession(remoteServer, listener, channel); | ||
102 | - session.initInputStream(); | ||
103 | - | ||
104 | - ClusterRpcServiceGrpc.ClusterRpcServiceStub stub = ClusterRpcServiceGrpc.newStub(channel); | ||
105 | - StreamObserver<ClusterAPIProtos.ClusterMessage> outputStream = stub.handleMsgs(session.getInputStream()); | ||
106 | - | ||
107 | - session.setOutputStream(outputStream); | ||
108 | - session.initOutputStream(); | ||
109 | - outputStream.onNext(toConnectMsg()); | ||
110 | - } | ||
111 | - } | ||
112 | - | ||
113 | - public static class ActorCreator extends ContextBasedCreator<RpcSessionActor> { | ||
114 | - private static final long serialVersionUID = 1L; | ||
115 | - | ||
116 | - private final UUID sessionId; | ||
117 | - | ||
118 | - public ActorCreator(ActorSystemContext context, UUID sessionId) { | ||
119 | - super(context); | ||
120 | - this.sessionId = sessionId; | ||
121 | - } | ||
122 | - | ||
123 | - @Override | ||
124 | - public RpcSessionActor create() { | ||
125 | - return new RpcSessionActor(context, sessionId); | ||
126 | - } | ||
127 | - } | ||
128 | - | ||
129 | - private ClusterAPIProtos.ClusterMessage toConnectMsg() { | ||
130 | - ServerAddress instance = systemContext.getDiscoveryService().getCurrentServer().getServerAddress(); | ||
131 | - return ClusterAPIProtos.ClusterMessage.newBuilder().setMessageType(CONNECT_RPC_MESSAGE).setServerAddress( | ||
132 | - ClusterAPIProtos.ServerAddress.newBuilder().setHost(instance.getHost()) | ||
133 | - .setPort(instance.getPort()).build()).build(); | ||
134 | - } | ||
135 | -} |
@@ -17,18 +17,13 @@ package org.thingsboard.server.actors.ruleChain; | @@ -17,18 +17,13 @@ package org.thingsboard.server.actors.ruleChain; | ||
17 | 17 | ||
18 | import akka.actor.ActorRef; | 18 | import akka.actor.ActorRef; |
19 | import com.datastax.driver.core.ResultSetFuture; | 19 | import com.datastax.driver.core.ResultSetFuture; |
20 | -import com.datastax.driver.core.utils.UUIDs; | ||
21 | import com.fasterxml.jackson.core.JsonProcessingException; | 20 | import com.fasterxml.jackson.core.JsonProcessingException; |
22 | import com.fasterxml.jackson.databind.ObjectMapper; | 21 | import com.fasterxml.jackson.databind.ObjectMapper; |
23 | -import com.fasterxml.jackson.databind.node.ObjectNode; | ||
24 | import io.netty.channel.EventLoopGroup; | 22 | import io.netty.channel.EventLoopGroup; |
23 | +import lombok.extern.slf4j.Slf4j; | ||
25 | import org.springframework.data.redis.core.RedisTemplate; | 24 | import org.springframework.data.redis.core.RedisTemplate; |
26 | -import org.springframework.util.StringUtils; | ||
27 | import org.thingsboard.common.util.ListeningExecutor; | 25 | import org.thingsboard.common.util.ListeningExecutor; |
28 | import org.thingsboard.rule.engine.api.MailService; | 26 | import org.thingsboard.rule.engine.api.MailService; |
29 | -import org.thingsboard.rule.engine.api.RuleChainTransactionService; | ||
30 | -import org.thingsboard.rule.engine.api.RuleEngineDeviceRpcRequest; | ||
31 | -import org.thingsboard.rule.engine.api.RuleEngineDeviceRpcResponse; | ||
32 | import org.thingsboard.rule.engine.api.RuleEngineRpcService; | 27 | import org.thingsboard.rule.engine.api.RuleEngineRpcService; |
33 | import org.thingsboard.rule.engine.api.RuleEngineTelemetryService; | 28 | import org.thingsboard.rule.engine.api.RuleEngineTelemetryService; |
34 | import org.thingsboard.rule.engine.api.ScriptEngine; | 29 | import org.thingsboard.rule.engine.api.ScriptEngine; |
@@ -40,19 +35,15 @@ import org.thingsboard.server.common.data.DataConstants; | @@ -40,19 +35,15 @@ import org.thingsboard.server.common.data.DataConstants; | ||
40 | import org.thingsboard.server.common.data.Device; | 35 | import org.thingsboard.server.common.data.Device; |
41 | import org.thingsboard.server.common.data.alarm.Alarm; | 36 | import org.thingsboard.server.common.data.alarm.Alarm; |
42 | import org.thingsboard.server.common.data.asset.Asset; | 37 | import org.thingsboard.server.common.data.asset.Asset; |
43 | -import org.thingsboard.server.common.data.id.DeviceId; | ||
44 | import org.thingsboard.server.common.data.id.EntityId; | 38 | import org.thingsboard.server.common.data.id.EntityId; |
39 | +import org.thingsboard.server.common.data.id.RuleChainId; | ||
45 | import org.thingsboard.server.common.data.id.RuleNodeId; | 40 | import org.thingsboard.server.common.data.id.RuleNodeId; |
46 | import org.thingsboard.server.common.data.id.TenantId; | 41 | import org.thingsboard.server.common.data.id.TenantId; |
47 | -import org.thingsboard.server.common.data.rpc.ToDeviceRpcRequestBody; | ||
48 | import org.thingsboard.server.common.data.rule.RuleNode; | 42 | import org.thingsboard.server.common.data.rule.RuleNode; |
49 | import org.thingsboard.server.common.msg.TbMsg; | 43 | import org.thingsboard.server.common.msg.TbMsg; |
50 | import org.thingsboard.server.common.msg.TbMsgMetaData; | 44 | import org.thingsboard.server.common.msg.TbMsgMetaData; |
51 | -import org.thingsboard.server.common.msg.cluster.SendToClusterMsg; | ||
52 | -import org.thingsboard.server.common.msg.cluster.ServerAddress; | ||
53 | -import org.thingsboard.server.common.msg.cluster.ServerType; | ||
54 | -import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest; | ||
55 | -import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg; | 45 | +import org.thingsboard.server.common.msg.queue.ServiceType; |
46 | +import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; | ||
56 | import org.thingsboard.server.dao.alarm.AlarmService; | 47 | import org.thingsboard.server.dao.alarm.AlarmService; |
57 | import org.thingsboard.server.dao.asset.AssetService; | 48 | import org.thingsboard.server.dao.asset.AssetService; |
58 | import org.thingsboard.server.dao.attributes.AttributesService; | 49 | import org.thingsboard.server.dao.attributes.AttributesService; |
@@ -67,11 +58,13 @@ import org.thingsboard.server.dao.rule.RuleChainService; | @@ -67,11 +58,13 @@ import org.thingsboard.server.dao.rule.RuleChainService; | ||
67 | import org.thingsboard.server.dao.tenant.TenantService; | 58 | import org.thingsboard.server.dao.tenant.TenantService; |
68 | import org.thingsboard.server.dao.timeseries.TimeseriesService; | 59 | import org.thingsboard.server.dao.timeseries.TimeseriesService; |
69 | import org.thingsboard.server.dao.user.UserService; | 60 | import org.thingsboard.server.dao.user.UserService; |
61 | +import org.thingsboard.server.gen.transport.TransportProtos; | ||
62 | +import org.thingsboard.server.queue.TbQueueCallback; | ||
63 | +import org.thingsboard.server.queue.TbQueueMsgMetadata; | ||
70 | import org.thingsboard.server.service.script.RuleNodeJsScriptEngine; | 64 | import org.thingsboard.server.service.script.RuleNodeJsScriptEngine; |
71 | import scala.concurrent.duration.Duration; | 65 | import scala.concurrent.duration.Duration; |
72 | 66 | ||
73 | import java.util.Collections; | 67 | import java.util.Collections; |
74 | -import java.util.Optional; | ||
75 | import java.util.Set; | 68 | import java.util.Set; |
76 | import java.util.concurrent.TimeUnit; | 69 | import java.util.concurrent.TimeUnit; |
77 | import java.util.function.Consumer; | 70 | import java.util.function.Consumer; |
@@ -79,6 +72,7 @@ import java.util.function.Consumer; | @@ -79,6 +72,7 @@ import java.util.function.Consumer; | ||
79 | /** | 72 | /** |
80 | * Created by ashvayka on 19.03.18. | 73 | * Created by ashvayka on 19.03.18. |
81 | */ | 74 | */ |
75 | +@Slf4j | ||
82 | class DefaultTbContext implements TbContext { | 76 | class DefaultTbContext implements TbContext { |
83 | 77 | ||
84 | public final static ObjectMapper mapper = new ObjectMapper(); | 78 | public final static ObjectMapper mapper = new ObjectMapper(); |
@@ -92,6 +86,11 @@ class DefaultTbContext implements TbContext { | @@ -92,6 +86,11 @@ class DefaultTbContext implements TbContext { | ||
92 | } | 86 | } |
93 | 87 | ||
94 | @Override | 88 | @Override |
89 | + public void tellSuccess(TbMsg msg) { | ||
90 | + tellNext(msg, Collections.singleton(TbRelationTypes.SUCCESS), null); | ||
91 | + } | ||
92 | + | ||
93 | + @Override | ||
95 | public void tellNext(TbMsg msg, String relationType) { | 94 | public void tellNext(TbMsg msg, String relationType) { |
96 | tellNext(msg, Collections.singleton(relationType), null); | 95 | tellNext(msg, Collections.singleton(relationType), null); |
97 | } | 96 | } |
@@ -101,16 +100,11 @@ class DefaultTbContext implements TbContext { | @@ -101,16 +100,11 @@ class DefaultTbContext implements TbContext { | ||
101 | tellNext(msg, relationTypes, null); | 100 | tellNext(msg, relationTypes, null); |
102 | } | 101 | } |
103 | 102 | ||
104 | - @Override | ||
105 | - public void tellNext(TbMsg msg, String relationType, Throwable th) { | ||
106 | - tellNext(msg, Collections.singleton(relationType), th); | ||
107 | - } | ||
108 | - | ||
109 | private void tellNext(TbMsg msg, Set<String> relationTypes, Throwable th) { | 103 | private void tellNext(TbMsg msg, Set<String> relationTypes, Throwable th) { |
110 | if (nodeCtx.getSelf().isDebugMode()) { | 104 | if (nodeCtx.getSelf().isDebugMode()) { |
111 | relationTypes.forEach(relationType -> mainCtx.persistDebugOutput(nodeCtx.getTenantId(), nodeCtx.getSelf().getId(), msg, relationType, th)); | 105 | relationTypes.forEach(relationType -> mainCtx.persistDebugOutput(nodeCtx.getTenantId(), nodeCtx.getSelf().getId(), msg, relationType, th)); |
112 | } | 106 | } |
113 | - nodeCtx.getChainActor().tell(new RuleNodeToRuleChainTellNextMsg(nodeCtx.getSelf().getId(), relationTypes, msg), nodeCtx.getSelfActor()); | 107 | + nodeCtx.getChainActor().tell(new RuleNodeToRuleChainTellNextMsg(nodeCtx.getSelf().getId(), relationTypes, msg, th != null ? th.getMessage() : null), nodeCtx.getSelfActor()); |
114 | } | 108 | } |
115 | 109 | ||
116 | @Override | 110 | @Override |
@@ -120,9 +114,93 @@ class DefaultTbContext implements TbContext { | @@ -120,9 +114,93 @@ class DefaultTbContext implements TbContext { | ||
120 | } | 114 | } |
121 | 115 | ||
122 | @Override | 116 | @Override |
117 | + public void enqueue(TbMsg tbMsg, Runnable onSuccess, Consumer<Throwable> onFailure) { | ||
118 | + TopicPartitionInfo tpi = mainCtx.resolve(ServiceType.TB_RULE_ENGINE, getTenantId(), tbMsg.getOriginator()); | ||
119 | + enqueue(tpi, tbMsg, onFailure, onSuccess); | ||
120 | + } | ||
121 | + | ||
122 | + @Override | ||
123 | + public void enqueue(TbMsg tbMsg, String queueName, Runnable onSuccess, Consumer<Throwable> onFailure) { | ||
124 | + TopicPartitionInfo tpi = mainCtx.resolve(ServiceType.TB_RULE_ENGINE, queueName, getTenantId(), tbMsg.getOriginator()); | ||
125 | + enqueue(tpi, tbMsg, onFailure, onSuccess); | ||
126 | + } | ||
127 | + | ||
128 | + private void enqueue(TopicPartitionInfo tpi, TbMsg tbMsg, Consumer<Throwable> onFailure, Runnable onSuccess) { | ||
129 | + TransportProtos.ToRuleEngineMsg msg = TransportProtos.ToRuleEngineMsg.newBuilder() | ||
130 | + .setTenantIdMSB(getTenantId().getId().getMostSignificantBits()) | ||
131 | + .setTenantIdLSB(getTenantId().getId().getLeastSignificantBits()) | ||
132 | + .setTbMsg(TbMsg.toByteString(tbMsg)).build(); | ||
133 | + mainCtx.getClusterService().pushMsgToRuleEngine(tpi, tbMsg.getId(), msg, new SimpleTbQueueCallback(onSuccess, onFailure)); | ||
134 | + } | ||
135 | + | ||
136 | + @Override | ||
137 | + public void enqueueForTellFailure(TbMsg tbMsg, String failureMessage) { | ||
138 | + TopicPartitionInfo tpi = mainCtx.resolve(ServiceType.TB_RULE_ENGINE, getTenantId(), tbMsg.getOriginator()); | ||
139 | + enqueueForTellNext(tpi, tbMsg, Collections.singleton(TbRelationTypes.FAILURE), failureMessage, null, null); | ||
140 | + } | ||
141 | + | ||
142 | + @Override | ||
143 | + public void enqueueForTellNext(TbMsg tbMsg, String relationType) { | ||
144 | + TopicPartitionInfo tpi = mainCtx.resolve(ServiceType.TB_RULE_ENGINE, getTenantId(), tbMsg.getOriginator()); | ||
145 | + enqueueForTellNext(tpi, tbMsg, Collections.singleton(relationType), null, null, null); | ||
146 | + } | ||
147 | + | ||
148 | + @Override | ||
149 | + public void enqueueForTellNext(TbMsg tbMsg, Set<String> relationTypes) { | ||
150 | + TopicPartitionInfo tpi = mainCtx.resolve(ServiceType.TB_RULE_ENGINE, getTenantId(), tbMsg.getOriginator()); | ||
151 | + enqueueForTellNext(tpi, tbMsg, relationTypes, null, null, null); | ||
152 | + } | ||
153 | + | ||
154 | + @Override | ||
155 | + public void enqueueForTellNext(TbMsg tbMsg, String relationType, Runnable onSuccess, Consumer<Throwable> onFailure) { | ||
156 | + TopicPartitionInfo tpi = mainCtx.resolve(ServiceType.TB_RULE_ENGINE, getTenantId(), tbMsg.getOriginator()); | ||
157 | + enqueueForTellNext(tpi, tbMsg, Collections.singleton(relationType), null, onSuccess, onFailure); | ||
158 | + } | ||
159 | + | ||
160 | + @Override | ||
161 | + public void enqueueForTellNext(TbMsg tbMsg, Set<String> relationTypes, Runnable onSuccess, Consumer<Throwable> onFailure) { | ||
162 | + TopicPartitionInfo tpi = mainCtx.resolve(ServiceType.TB_RULE_ENGINE, getTenantId(), tbMsg.getOriginator()); | ||
163 | + enqueueForTellNext(tpi, tbMsg, relationTypes, null, onSuccess, onFailure); | ||
164 | + } | ||
165 | + | ||
166 | + @Override | ||
167 | + public void enqueueForTellNext(TbMsg tbMsg, String queueName, String relationType, Runnable onSuccess, Consumer<Throwable> onFailure) { | ||
168 | + TopicPartitionInfo tpi = mainCtx.resolve(ServiceType.TB_RULE_ENGINE, queueName, getTenantId(), tbMsg.getOriginator()); | ||
169 | + enqueueForTellNext(tpi, tbMsg, Collections.singleton(relationType), null, onSuccess, onFailure); | ||
170 | + } | ||
171 | + | ||
172 | + @Override | ||
173 | + public void enqueueForTellNext(TbMsg tbMsg, String queueName, Set<String> relationTypes, Runnable onSuccess, Consumer<Throwable> onFailure) { | ||
174 | + TopicPartitionInfo tpi = mainCtx.resolve(ServiceType.TB_RULE_ENGINE, queueName, getTenantId(), tbMsg.getOriginator()); | ||
175 | + enqueueForTellNext(tpi, tbMsg, relationTypes, null, onSuccess, onFailure); | ||
176 | + } | ||
177 | + | ||
178 | + private void enqueueForTellNext(TopicPartitionInfo tpi, TbMsg tbMsg, Set<String> relationTypes, String failureMessage, Runnable onSuccess, Consumer<Throwable> onFailure) { | ||
179 | + RuleChainId ruleChainId = nodeCtx.getSelf().getRuleChainId(); | ||
180 | + RuleNodeId ruleNodeId = nodeCtx.getSelf().getId(); | ||
181 | + tbMsg = TbMsg.newMsg(tbMsg, ruleChainId, ruleNodeId); | ||
182 | + TransportProtos.ToRuleEngineMsg.Builder msg = TransportProtos.ToRuleEngineMsg.newBuilder() | ||
183 | + .setTenantIdMSB(getTenantId().getId().getMostSignificantBits()) | ||
184 | + .setTenantIdLSB(getTenantId().getId().getLeastSignificantBits()) | ||
185 | + .setTbMsg(TbMsg.toByteString(tbMsg)) | ||
186 | + .addAllRelationTypes(relationTypes); | ||
187 | + if (failureMessage != null) { | ||
188 | + msg.setFailureMessage(failureMessage); | ||
189 | + } | ||
190 | + mainCtx.getClusterService().pushMsgToRuleEngine(tpi, tbMsg.getId(), msg.build(), new SimpleTbQueueCallback(onSuccess, onFailure)); | ||
191 | + } | ||
192 | + | ||
193 | + @Override | ||
194 | + public void ack(TbMsg tbMsg) { | ||
195 | + if (nodeCtx.getSelf().isDebugMode()) { | ||
196 | + mainCtx.persistDebugOutput(nodeCtx.getTenantId(), nodeCtx.getSelf().getId(), tbMsg, "ACK", null); | ||
197 | + } | ||
198 | + tbMsg.getCallback().onSuccess(); | ||
199 | + } | ||
200 | + | ||
201 | + @Override | ||
123 | public boolean isLocalEntity(EntityId entityId) { | 202 | public boolean isLocalEntity(EntityId entityId) { |
124 | - Optional<ServerAddress> address = mainCtx.getRoutingService().resolveById(entityId); | ||
125 | - return !address.isPresent(); | 203 | + return mainCtx.resolve(ServiceType.TB_RULE_ENGINE, getTenantId(), entityId).isMyPartition(); |
126 | } | 204 | } |
127 | 205 | ||
128 | private void scheduleMsgWithDelay(Object msg, long delayInMs, ActorRef target) { | 206 | private void scheduleMsgWithDelay(Object msg, long delayInMs, ActorRef target) { |
@@ -134,66 +212,48 @@ class DefaultTbContext implements TbContext { | @@ -134,66 +212,48 @@ class DefaultTbContext implements TbContext { | ||
134 | if (nodeCtx.getSelf().isDebugMode()) { | 212 | if (nodeCtx.getSelf().isDebugMode()) { |
135 | mainCtx.persistDebugOutput(nodeCtx.getTenantId(), nodeCtx.getSelf().getId(), msg, TbRelationTypes.FAILURE, th); | 213 | mainCtx.persistDebugOutput(nodeCtx.getTenantId(), nodeCtx.getSelf().getId(), msg, TbRelationTypes.FAILURE, th); |
136 | } | 214 | } |
137 | - nodeCtx.getChainActor().tell(new RuleNodeToRuleChainTellNextMsg(nodeCtx.getSelf().getId(), Collections.singleton(TbRelationTypes.FAILURE), msg), nodeCtx.getSelfActor()); | 215 | + nodeCtx.getChainActor().tell(new RuleNodeToRuleChainTellNextMsg(nodeCtx.getSelf().getId(), Collections.singleton(TbRelationTypes.FAILURE), |
216 | + msg, th != null ? th.getMessage() : null), nodeCtx.getSelfActor()); | ||
138 | } | 217 | } |
139 | 218 | ||
140 | - @Override | ||
141 | public void updateSelf(RuleNode self) { | 219 | public void updateSelf(RuleNode self) { |
142 | nodeCtx.setSelf(self); | 220 | nodeCtx.setSelf(self); |
143 | } | 221 | } |
144 | 222 | ||
145 | @Override | 223 | @Override |
146 | public TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, String data) { | 224 | public TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, String data) { |
147 | - return new TbMsg(UUIDs.timeBased(), type, originator, metaData.copy(), data, nodeCtx.getSelf().getRuleChainId(), nodeCtx.getSelf().getId(), mainCtx.getQueuePartitionId()); | 225 | + return TbMsg.newMsg(type, originator, metaData, data, nodeCtx.getSelf().getRuleChainId(), nodeCtx.getSelf().getId()); |
148 | } | 226 | } |
149 | 227 | ||
150 | @Override | 228 | @Override |
151 | public TbMsg transformMsg(TbMsg origMsg, String type, EntityId originator, TbMsgMetaData metaData, String data) { | 229 | public TbMsg transformMsg(TbMsg origMsg, String type, EntityId originator, TbMsgMetaData metaData, String data) { |
152 | - return new TbMsg(origMsg.getId(), type, originator, metaData.copy(), origMsg.getDataType(), data, origMsg.getTransactionData(), origMsg.getRuleChainId(), origMsg.getRuleNodeId(), mainCtx.getQueuePartitionId()); | ||
153 | - } | ||
154 | - | ||
155 | - @Override | ||
156 | - public void sendTbMsgToRuleEngine(TbMsg msg) { | ||
157 | - mainCtx.getActorService().onMsg(new SendToClusterMsg(msg.getOriginator(), new ServiceToRuleEngineMsg(getTenantId(), msg))); | 230 | + return TbMsg.transformMsg(origMsg, type, originator, metaData, data); |
158 | } | 231 | } |
159 | 232 | ||
160 | public TbMsg customerCreatedMsg(Customer customer, RuleNodeId ruleNodeId) { | 233 | public TbMsg customerCreatedMsg(Customer customer, RuleNodeId ruleNodeId) { |
161 | - try { | ||
162 | - ObjectNode entityNode = mapper.valueToTree(customer); | ||
163 | - return new TbMsg(UUIDs.timeBased(), DataConstants.ENTITY_CREATED, customer.getId(), getActionMetaData(ruleNodeId), mapper.writeValueAsString(entityNode), null, null, 0L); | ||
164 | - } catch (JsonProcessingException | IllegalArgumentException e) { | ||
165 | - throw new RuntimeException("Failed to process customer created msg: " + e); | ||
166 | - } | 234 | + return entityCreatedMsg(customer, customer.getId(), ruleNodeId); |
167 | } | 235 | } |
168 | 236 | ||
169 | public TbMsg deviceCreatedMsg(Device device, RuleNodeId ruleNodeId) { | 237 | public TbMsg deviceCreatedMsg(Device device, RuleNodeId ruleNodeId) { |
170 | - try { | ||
171 | - ObjectNode entityNode = mapper.valueToTree(device); | ||
172 | - return new TbMsg(UUIDs.timeBased(), DataConstants.ENTITY_CREATED, device.getId(), getActionMetaData(ruleNodeId), mapper.writeValueAsString(entityNode), null, null, 0L); | ||
173 | - } catch (JsonProcessingException | IllegalArgumentException e) { | ||
174 | - throw new RuntimeException("Failed to process device created msg: " + e); | ||
175 | - } | 238 | + return entityCreatedMsg(device, device.getId(), ruleNodeId); |
176 | } | 239 | } |
177 | 240 | ||
178 | public TbMsg assetCreatedMsg(Asset asset, RuleNodeId ruleNodeId) { | 241 | public TbMsg assetCreatedMsg(Asset asset, RuleNodeId ruleNodeId) { |
179 | - try { | ||
180 | - ObjectNode entityNode = mapper.valueToTree(asset); | ||
181 | - return new TbMsg(UUIDs.timeBased(), DataConstants.ENTITY_CREATED, asset.getId(), getActionMetaData(ruleNodeId), mapper.writeValueAsString(entityNode), null, null, 0L); | ||
182 | - } catch (JsonProcessingException | IllegalArgumentException e) { | ||
183 | - throw new RuntimeException("Failed to process asset created msg: " + e); | ||
184 | - } | 242 | + return entityCreatedMsg(asset, asset.getId(), ruleNodeId); |
185 | } | 243 | } |
186 | 244 | ||
187 | public TbMsg alarmCreatedMsg(Alarm alarm, RuleNodeId ruleNodeId) { | 245 | public TbMsg alarmCreatedMsg(Alarm alarm, RuleNodeId ruleNodeId) { |
246 | + return entityCreatedMsg(alarm, alarm.getId(), ruleNodeId); | ||
247 | + } | ||
248 | + | ||
249 | + public <E, I extends EntityId> TbMsg entityCreatedMsg(E entity, I id, RuleNodeId ruleNodeId) { | ||
188 | try { | 250 | try { |
189 | - ObjectNode entityNode = mapper.valueToTree(alarm); | ||
190 | - return new TbMsg(UUIDs.timeBased(), DataConstants.ENTITY_CREATED, alarm.getId(), getActionMetaData(ruleNodeId), mapper.writeValueAsString(entityNode), null, null, 0L); | 251 | + return TbMsg.newMsg(DataConstants.ENTITY_CREATED, id, getActionMetaData(ruleNodeId), mapper.writeValueAsString(mapper.valueToTree(entity))); |
191 | } catch (JsonProcessingException | IllegalArgumentException e) { | 252 | } catch (JsonProcessingException | IllegalArgumentException e) { |
192 | - throw new RuntimeException("Failed to process alarm created msg: " + e); | 253 | + throw new RuntimeException("Failed to process " + id.getEntityType().name().toLowerCase() + " created msg: " + e); |
193 | } | 254 | } |
194 | } | 255 | } |
195 | 256 | ||
196 | - | ||
197 | @Override | 257 | @Override |
198 | public RuleNodeId getSelfId() { | 258 | public RuleNodeId getSelfId() { |
199 | return nodeCtx.getSelf().getId(); | 259 | return nodeCtx.getSelf().getId(); |
@@ -251,8 +311,8 @@ class DefaultTbContext implements TbContext { | @@ -251,8 +311,8 @@ class DefaultTbContext implements TbContext { | ||
251 | } | 311 | } |
252 | 312 | ||
253 | @Override | 313 | @Override |
254 | - public String getNodeId() { | ||
255 | - return mainCtx.getNodeIdProvider().getNodeId(); | 314 | + public String getServiceId() { |
315 | + return mainCtx.getServiceInfoProvider().getServiceId(); | ||
256 | } | 316 | } |
257 | 317 | ||
258 | @Override | 318 | @Override |
@@ -321,11 +381,6 @@ class DefaultTbContext implements TbContext { | @@ -321,11 +381,6 @@ class DefaultTbContext implements TbContext { | ||
321 | } | 381 | } |
322 | 382 | ||
323 | @Override | 383 | @Override |
324 | - public RuleChainTransactionService getRuleChainTransactionService() { | ||
325 | - return mainCtx.getRuleChainTransactionService(); | ||
326 | - } | ||
327 | - | ||
328 | - @Override | ||
329 | public EventLoopGroup getSharedEventLoop() { | 384 | public EventLoopGroup getSharedEventLoop() { |
330 | return mainCtx.getSharedEventLoopGroupService().getSharedEventLoopGroup(); | 385 | return mainCtx.getSharedEventLoopGroupService().getSharedEventLoopGroup(); |
331 | } | 386 | } |
@@ -341,35 +396,7 @@ class DefaultTbContext implements TbContext { | @@ -341,35 +396,7 @@ class DefaultTbContext implements TbContext { | ||
341 | 396 | ||
342 | @Override | 397 | @Override |
343 | public RuleEngineRpcService getRpcService() { | 398 | public RuleEngineRpcService getRpcService() { |
344 | - return new RuleEngineRpcService() { | ||
345 | - @Override | ||
346 | - public void sendRpcReply(DeviceId deviceId, int requestId, String body) { | ||
347 | - mainCtx.getDeviceRpcService().sendReplyToRpcCallFromDevice(nodeCtx.getTenantId(), deviceId, requestId, body); | ||
348 | - } | ||
349 | - | ||
350 | - @Override | ||
351 | - public void sendRpcRequest(RuleEngineDeviceRpcRequest src, Consumer<RuleEngineDeviceRpcResponse> consumer) { | ||
352 | - ToDeviceRpcRequest request = new ToDeviceRpcRequest(src.getRequestUUID(), nodeCtx.getTenantId(), src.getDeviceId(), | ||
353 | - src.isOneway(), src.getExpirationTime(), new ToDeviceRpcRequestBody(src.getMethod(), src.getBody())); | ||
354 | - mainCtx.getDeviceRpcService().forwardServerSideRPCRequestToDeviceActor(request, response -> { | ||
355 | - if (src.isRestApiCall()) { | ||
356 | - ServerAddress requestOriginAddress; | ||
357 | - if (!StringUtils.isEmpty(src.getOriginHost())) { | ||
358 | - requestOriginAddress = new ServerAddress(src.getOriginHost(), src.getOriginPort(), ServerType.CORE); | ||
359 | - } else { | ||
360 | - requestOriginAddress = mainCtx.getRoutingService().getCurrentServer(); | ||
361 | - } | ||
362 | - mainCtx.getDeviceRpcService().processResponseToServerSideRPCRequestFromRuleEngine(requestOriginAddress, response); | ||
363 | - } | ||
364 | - consumer.accept(RuleEngineDeviceRpcResponse.builder() | ||
365 | - .deviceId(src.getDeviceId()) | ||
366 | - .requestId(src.getRequestId()) | ||
367 | - .error(response.getError()) | ||
368 | - .response(response.getResponse()) | ||
369 | - .build()); | ||
370 | - }); | ||
371 | - } | ||
372 | - }; | 399 | + return mainCtx.getTbRuleEngineDeviceRpcService(); |
373 | } | 400 | } |
374 | 401 | ||
375 | @Override | 402 | @Override |
@@ -387,10 +414,6 @@ class DefaultTbContext implements TbContext { | @@ -387,10 +414,6 @@ class DefaultTbContext implements TbContext { | ||
387 | return mainCtx.getRedisTemplate(); | 414 | return mainCtx.getRedisTemplate(); |
388 | } | 415 | } |
389 | 416 | ||
390 | - @Override | ||
391 | - public String getServerAddress() { | ||
392 | - return mainCtx.getServerAddress(); | ||
393 | - } | ||
394 | 417 | ||
395 | private TbMsgMetaData getActionMetaData(RuleNodeId ruleNodeId) { | 418 | private TbMsgMetaData getActionMetaData(RuleNodeId ruleNodeId) { |
396 | TbMsgMetaData metaData = new TbMsgMetaData(); | 419 | TbMsgMetaData metaData = new TbMsgMetaData(); |
@@ -398,4 +421,29 @@ class DefaultTbContext implements TbContext { | @@ -398,4 +421,29 @@ class DefaultTbContext implements TbContext { | ||
398 | return metaData; | 421 | return metaData; |
399 | } | 422 | } |
400 | 423 | ||
424 | + private class SimpleTbQueueCallback implements TbQueueCallback { | ||
425 | + private final Runnable onSuccess; | ||
426 | + private final Consumer<Throwable> onFailure; | ||
427 | + | ||
428 | + public SimpleTbQueueCallback(Runnable onSuccess, Consumer<Throwable> onFailure) { | ||
429 | + this.onSuccess = onSuccess; | ||
430 | + this.onFailure = onFailure; | ||
431 | + } | ||
432 | + | ||
433 | + @Override | ||
434 | + public void onSuccess(TbQueueMsgMetadata metadata) { | ||
435 | + if (onSuccess != null) { | ||
436 | + onSuccess.run(); | ||
437 | + } | ||
438 | + } | ||
439 | + | ||
440 | + @Override | ||
441 | + public void onFailure(Throwable t) { | ||
442 | + if (onFailure != null) { | ||
443 | + onFailure.accept(t); | ||
444 | + } else { | ||
445 | + log.debug("[{}] Failed to put item into queue", nodeCtx.getTenantId(), t); | ||
446 | + } | ||
447 | + } | ||
448 | + } | ||
401 | } | 449 | } |
@@ -15,25 +15,25 @@ | @@ -15,25 +15,25 @@ | ||
15 | */ | 15 | */ |
16 | package org.thingsboard.server.actors.ruleChain; | 16 | package org.thingsboard.server.actors.ruleChain; |
17 | 17 | ||
18 | -import akka.actor.ActorInitializationException; | ||
19 | import akka.actor.OneForOneStrategy; | 18 | import akka.actor.OneForOneStrategy; |
20 | import akka.actor.SupervisorStrategy; | 19 | import akka.actor.SupervisorStrategy; |
21 | import org.thingsboard.server.actors.ActorSystemContext; | 20 | import org.thingsboard.server.actors.ActorSystemContext; |
22 | -import org.thingsboard.server.actors.device.DeviceActorToRuleEngineMsg; | ||
23 | import org.thingsboard.server.actors.service.ComponentActor; | 21 | import org.thingsboard.server.actors.service.ComponentActor; |
24 | import org.thingsboard.server.actors.service.ContextBasedCreator; | 22 | import org.thingsboard.server.actors.service.ContextBasedCreator; |
25 | import org.thingsboard.server.common.data.id.RuleChainId; | 23 | import org.thingsboard.server.common.data.id.RuleChainId; |
26 | import org.thingsboard.server.common.data.id.TenantId; | 24 | import org.thingsboard.server.common.data.id.TenantId; |
25 | +import org.thingsboard.server.common.data.rule.RuleChain; | ||
27 | import org.thingsboard.server.common.msg.TbActorMsg; | 26 | import org.thingsboard.server.common.msg.TbActorMsg; |
28 | import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; | 27 | import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; |
29 | -import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg; | 28 | +import org.thingsboard.server.common.msg.queue.PartitionChangeMsg; |
29 | +import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg; | ||
30 | import scala.concurrent.duration.Duration; | 30 | import scala.concurrent.duration.Duration; |
31 | 31 | ||
32 | public class RuleChainActor extends ComponentActor<RuleChainId, RuleChainActorMessageProcessor> { | 32 | public class RuleChainActor extends ComponentActor<RuleChainId, RuleChainActorMessageProcessor> { |
33 | 33 | ||
34 | - private RuleChainActor(ActorSystemContext systemContext, TenantId tenantId, RuleChainId ruleChainId) { | ||
35 | - super(systemContext, tenantId, ruleChainId); | ||
36 | - setProcessor(new RuleChainActorMessageProcessor(tenantId, ruleChainId, systemContext, | 34 | + private RuleChainActor(ActorSystemContext systemContext, TenantId tenantId, RuleChain ruleChain) { |
35 | + super(systemContext, tenantId, ruleChain.getId()); | ||
36 | + setProcessor(new RuleChainActorMessageProcessor(tenantId, ruleChain, systemContext, | ||
37 | context().parent(), context().self())); | 37 | context().parent(), context().self())); |
38 | } | 38 | } |
39 | 39 | ||
@@ -43,20 +43,17 @@ public class RuleChainActor extends ComponentActor<RuleChainId, RuleChainActorMe | @@ -43,20 +43,17 @@ public class RuleChainActor extends ComponentActor<RuleChainId, RuleChainActorMe | ||
43 | case COMPONENT_LIFE_CYCLE_MSG: | 43 | case COMPONENT_LIFE_CYCLE_MSG: |
44 | onComponentLifecycleMsg((ComponentLifecycleMsg) msg); | 44 | onComponentLifecycleMsg((ComponentLifecycleMsg) msg); |
45 | break; | 45 | break; |
46 | - case SERVICE_TO_RULE_ENGINE_MSG: | ||
47 | - processor.onServiceToRuleEngineMsg((ServiceToRuleEngineMsg) msg); | ||
48 | - break; | ||
49 | - case DEVICE_ACTOR_TO_RULE_ENGINE_MSG: | ||
50 | - processor.onDeviceActorToRuleEngineMsg((DeviceActorToRuleEngineMsg) msg); | 46 | + case QUEUE_TO_RULE_ENGINE_MSG: |
47 | + processor.onQueueToRuleEngineMsg((QueueToRuleEngineMsg) msg); | ||
51 | break; | 48 | break; |
52 | case RULE_TO_RULE_CHAIN_TELL_NEXT_MSG: | 49 | case RULE_TO_RULE_CHAIN_TELL_NEXT_MSG: |
53 | - case REMOTE_TO_RULE_CHAIN_TELL_NEXT_MSG: | ||
54 | processor.onTellNext((RuleNodeToRuleChainTellNextMsg) msg); | 50 | processor.onTellNext((RuleNodeToRuleChainTellNextMsg) msg); |
55 | break; | 51 | break; |
56 | case RULE_CHAIN_TO_RULE_CHAIN_MSG: | 52 | case RULE_CHAIN_TO_RULE_CHAIN_MSG: |
57 | processor.onRuleChainToRuleChainMsg((RuleChainToRuleChainMsg) msg); | 53 | processor.onRuleChainToRuleChainMsg((RuleChainToRuleChainMsg) msg); |
58 | break; | 54 | break; |
59 | - case CLUSTER_EVENT_MSG: | 55 | + case PARTITION_CHANGE_MSG: |
56 | + processor.onPartitionChangeMsg((PartitionChangeMsg) msg); | ||
60 | break; | 57 | break; |
61 | case STATS_PERSIST_TICK_MSG: | 58 | case STATS_PERSIST_TICK_MSG: |
62 | onStatsPersistTick(id); | 59 | onStatsPersistTick(id); |
@@ -71,17 +68,17 @@ public class RuleChainActor extends ComponentActor<RuleChainId, RuleChainActorMe | @@ -71,17 +68,17 @@ public class RuleChainActor extends ComponentActor<RuleChainId, RuleChainActorMe | ||
71 | private static final long serialVersionUID = 1L; | 68 | private static final long serialVersionUID = 1L; |
72 | 69 | ||
73 | private final TenantId tenantId; | 70 | private final TenantId tenantId; |
74 | - private final RuleChainId ruleChainId; | 71 | + private final RuleChain ruleChain; |
75 | 72 | ||
76 | - public ActorCreator(ActorSystemContext context, TenantId tenantId, RuleChainId pluginId) { | 73 | + public ActorCreator(ActorSystemContext context, TenantId tenantId, RuleChain ruleChain) { |
77 | super(context); | 74 | super(context); |
78 | this.tenantId = tenantId; | 75 | this.tenantId = tenantId; |
79 | - this.ruleChainId = pluginId; | 76 | + this.ruleChain = ruleChain; |
80 | } | 77 | } |
81 | 78 | ||
82 | @Override | 79 | @Override |
83 | public RuleChainActor create() { | 80 | public RuleChainActor create() { |
84 | - return new RuleChainActor(context, tenantId, ruleChainId); | 81 | + return new RuleChainActor(context, tenantId, ruleChain); |
85 | } | 82 | } |
86 | } | 83 | } |
87 | 84 |
@@ -18,14 +18,9 @@ package org.thingsboard.server.actors.ruleChain; | @@ -18,14 +18,9 @@ package org.thingsboard.server.actors.ruleChain; | ||
18 | import akka.actor.ActorContext; | 18 | import akka.actor.ActorContext; |
19 | import akka.actor.ActorRef; | 19 | import akka.actor.ActorRef; |
20 | import akka.actor.Props; | 20 | import akka.actor.Props; |
21 | -import akka.event.LoggingAdapter; | ||
22 | -import com.datastax.driver.core.utils.UUIDs; | ||
23 | - | ||
24 | -import java.util.Optional; | ||
25 | - | ||
26 | import lombok.extern.slf4j.Slf4j; | 21 | import lombok.extern.slf4j.Slf4j; |
22 | +import org.thingsboard.rule.engine.api.TbRelationTypes; | ||
27 | import org.thingsboard.server.actors.ActorSystemContext; | 23 | import org.thingsboard.server.actors.ActorSystemContext; |
28 | -import org.thingsboard.server.actors.device.DeviceActorToRuleEngineMsg; | ||
29 | import org.thingsboard.server.actors.service.DefaultActorService; | 24 | import org.thingsboard.server.actors.service.DefaultActorService; |
30 | import org.thingsboard.server.actors.shared.ComponentMsgProcessor; | 25 | import org.thingsboard.server.actors.shared.ComponentMsgProcessor; |
31 | import org.thingsboard.server.common.data.EntityType; | 26 | import org.thingsboard.server.common.data.EntityType; |
@@ -39,11 +34,19 @@ import org.thingsboard.server.common.data.relation.EntityRelation; | @@ -39,11 +34,19 @@ import org.thingsboard.server.common.data.relation.EntityRelation; | ||
39 | import org.thingsboard.server.common.data.rule.RuleChain; | 34 | import org.thingsboard.server.common.data.rule.RuleChain; |
40 | import org.thingsboard.server.common.data.rule.RuleNode; | 35 | import org.thingsboard.server.common.data.rule.RuleNode; |
41 | import org.thingsboard.server.common.msg.TbMsg; | 36 | import org.thingsboard.server.common.msg.TbMsg; |
42 | -import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; | ||
43 | -import org.thingsboard.server.common.msg.cluster.ServerAddress; | ||
44 | import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; | 37 | import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; |
45 | -import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg; | 38 | +import org.thingsboard.server.common.msg.queue.PartitionChangeMsg; |
39 | +import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg; | ||
40 | +import org.thingsboard.server.common.msg.queue.RuleEngineException; | ||
41 | +import org.thingsboard.server.common.msg.queue.RuleNodeException; | ||
42 | +import org.thingsboard.server.common.msg.queue.ServiceType; | ||
43 | +import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; | ||
46 | import org.thingsboard.server.dao.rule.RuleChainService; | 44 | import org.thingsboard.server.dao.rule.RuleChainService; |
45 | +import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; | ||
46 | +import org.thingsboard.server.queue.TbQueueCallback; | ||
47 | +import org.thingsboard.server.queue.common.MultipleTbQueueTbMsgCallbackWrapper; | ||
48 | +import org.thingsboard.server.queue.common.TbQueueTbMsgCallbackWrapper; | ||
49 | +import org.thingsboard.server.service.queue.TbClusterService; | ||
47 | 50 | ||
48 | import java.util.ArrayList; | 51 | import java.util.ArrayList; |
49 | import java.util.Collections; | 52 | import java.util.Collections; |
@@ -59,27 +62,28 @@ import java.util.stream.Collectors; | @@ -59,27 +62,28 @@ import java.util.stream.Collectors; | ||
59 | @Slf4j | 62 | @Slf4j |
60 | public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleChainId> { | 63 | public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleChainId> { |
61 | 64 | ||
62 | - private static final long DEFAULT_CLUSTER_PARTITION = 0L; | ||
63 | private final ActorRef parent; | 65 | private final ActorRef parent; |
64 | private final ActorRef self; | 66 | private final ActorRef self; |
65 | private final Map<RuleNodeId, RuleNodeCtx> nodeActors; | 67 | private final Map<RuleNodeId, RuleNodeCtx> nodeActors; |
66 | private final Map<RuleNodeId, List<RuleNodeRelation>> nodeRoutes; | 68 | private final Map<RuleNodeId, List<RuleNodeRelation>> nodeRoutes; |
67 | private final RuleChainService service; | 69 | private final RuleChainService service; |
70 | + private final TbClusterService clusterService; | ||
71 | + private String ruleChainName; | ||
68 | 72 | ||
69 | private RuleNodeId firstId; | 73 | private RuleNodeId firstId; |
70 | private RuleNodeCtx firstNode; | 74 | private RuleNodeCtx firstNode; |
71 | private boolean started; | 75 | private boolean started; |
72 | - private String ruleChainName; | ||
73 | 76 | ||
74 | - RuleChainActorMessageProcessor(TenantId tenantId, RuleChainId ruleChainId, ActorSystemContext systemContext | 77 | + RuleChainActorMessageProcessor(TenantId tenantId, RuleChain ruleChain, ActorSystemContext systemContext |
75 | , ActorRef parent, ActorRef self) { | 78 | , ActorRef parent, ActorRef self) { |
76 | - super(systemContext, tenantId, ruleChainId); | 79 | + super(systemContext, tenantId, ruleChain.getId()); |
80 | + this.ruleChainName = ruleChain.getName(); | ||
77 | this.parent = parent; | 81 | this.parent = parent; |
78 | this.self = self; | 82 | this.self = self; |
79 | this.nodeActors = new HashMap<>(); | 83 | this.nodeActors = new HashMap<>(); |
80 | this.nodeRoutes = new HashMap<>(); | 84 | this.nodeRoutes = new HashMap<>(); |
81 | this.service = systemContext.getRuleChainService(); | 85 | this.service = systemContext.getRuleChainService(); |
82 | - this.ruleChainName = ruleChainId.toString(); | 86 | + this.clusterService = systemContext.getClusterService(); |
83 | } | 87 | } |
84 | 88 | ||
85 | @Override | 89 | @Override |
@@ -92,7 +96,6 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh | @@ -92,7 +96,6 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh | ||
92 | if (!started) { | 96 | if (!started) { |
93 | RuleChain ruleChain = service.findRuleChainById(tenantId, entityId); | 97 | RuleChain ruleChain = service.findRuleChainById(tenantId, entityId); |
94 | if (ruleChain != null) { | 98 | if (ruleChain != null) { |
95 | - ruleChainName = ruleChain.getName(); | ||
96 | List<RuleNode> ruleNodeList = service.getRuleChainNodes(tenantId, entityId); | 99 | List<RuleNode> ruleNodeList = service.getRuleChainNodes(tenantId, entityId); |
97 | log.trace("[{}][{}] Starting rule chain with {} nodes", tenantId, entityId, ruleNodeList.size()); | 100 | log.trace("[{}][{}] Starting rule chain with {} nodes", tenantId, entityId, ruleNodeList.size()); |
98 | // Creating and starting the actors; | 101 | // Creating and starting the actors; |
@@ -152,8 +155,8 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh | @@ -152,8 +155,8 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh | ||
152 | } | 155 | } |
153 | 156 | ||
154 | @Override | 157 | @Override |
155 | - public void onClusterEventMsg(ClusterEventMsg msg) { | ||
156 | - | 158 | + public void onPartitionChangeMsg(PartitionChangeMsg msg) { |
159 | + nodeActors.values().stream().map(RuleNodeCtx::getSelfActor).forEach(actorRef -> actorRef.tell(msg, self)); | ||
157 | } | 160 | } |
158 | 161 | ||
159 | private ActorRef createRuleNodeActor(ActorContext context, RuleNode ruleNode) { | 162 | private ActorRef createRuleNodeActor(ActorContext context, RuleNode ruleNode) { |
@@ -192,100 +195,123 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh | @@ -192,100 +195,123 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh | ||
192 | state = ComponentLifecycleState.ACTIVE; | 195 | state = ComponentLifecycleState.ACTIVE; |
193 | } | 196 | } |
194 | 197 | ||
195 | - void onServiceToRuleEngineMsg(ServiceToRuleEngineMsg envelope) { | ||
196 | - log.trace("[{}][{}] Processing message [{}]: {}", entityId, firstId, envelope.getTbMsg().getId(), envelope.getTbMsg()); | ||
197 | - checkActive(); | ||
198 | - if (firstNode != null) { | ||
199 | - log.trace("[{}][{}] Pushing message to first rule node", entityId, firstId); | ||
200 | - pushMsgToNode(firstNode, enrichWithRuleChainId(envelope.getTbMsg()), ""); | ||
201 | - } | ||
202 | - } | ||
203 | - | ||
204 | - void onDeviceActorToRuleEngineMsg(DeviceActorToRuleEngineMsg envelope) { | ||
205 | - checkActive(); | ||
206 | - if (firstNode != null) { | ||
207 | - pushMsgToNode(firstNode, enrichWithRuleChainId(envelope.getTbMsg()), ""); | 198 | + void onQueueToRuleEngineMsg(QueueToRuleEngineMsg envelope) { |
199 | + TbMsg msg = envelope.getTbMsg(); | ||
200 | + log.trace("[{}][{}] Processing message [{}]: {}", entityId, firstId, msg.getId(), msg); | ||
201 | + if (envelope.getRelationTypes() == null || envelope.getRelationTypes().isEmpty()) { | ||
202 | + try { | ||
203 | + checkActive(); | ||
204 | + RuleNodeId targetId = msg.getRuleNodeId(); | ||
205 | + RuleNodeCtx targetCtx; | ||
206 | + if (targetId == null) { | ||
207 | + targetCtx = firstNode; | ||
208 | + msg = msg.copyWithRuleChainId(entityId); | ||
209 | + } else { | ||
210 | + targetCtx = nodeActors.get(targetId); | ||
211 | + } | ||
212 | + if (targetCtx != null) { | ||
213 | + log.trace("[{}][{}] Pushing message to target rule node", entityId, targetId); | ||
214 | + pushMsgToNode(targetCtx, msg, ""); | ||
215 | + } else { | ||
216 | + log.trace("[{}][{}] Rule node does not exist. Probably old message", entityId, targetId); | ||
217 | + msg.getCallback().onSuccess(); | ||
218 | + } | ||
219 | + } catch (Exception e) { | ||
220 | + envelope.getTbMsg().getCallback().onFailure(new RuleEngineException(e.getMessage())); | ||
221 | + } | ||
222 | + } else { | ||
223 | + onTellNext(envelope.getTbMsg(), envelope.getTbMsg().getRuleNodeId(), envelope.getRelationTypes(), envelope.getFailureMessage()); | ||
208 | } | 224 | } |
209 | } | 225 | } |
210 | 226 | ||
211 | void onRuleChainToRuleChainMsg(RuleChainToRuleChainMsg envelope) { | 227 | void onRuleChainToRuleChainMsg(RuleChainToRuleChainMsg envelope) { |
212 | checkActive(); | 228 | checkActive(); |
213 | - if (envelope.isEnqueue()) { | ||
214 | - if (firstNode != null) { | ||
215 | - pushMsgToNode(firstNode, enrichWithRuleChainId(envelope.getMsg()), envelope.getFromRelationType()); | ||
216 | - } | 229 | + if (firstNode != null) { |
230 | + pushMsgToNode(firstNode, envelope.getMsg(), envelope.getFromRelationType()); | ||
217 | } else { | 231 | } else { |
218 | - if (firstNode != null) { | ||
219 | - pushMsgToNode(firstNode, envelope.getMsg(), envelope.getFromRelationType()); | ||
220 | - } else { | ||
221 | -// TODO: Ack this message in Kafka | ||
222 | -// TbMsg msg = envelope.getMsg(); | ||
223 | -// EntityId ackId = msg.getRuleNodeId() != null ? msg.getRuleNodeId() : msg.getRuleChainId(); | ||
224 | -// queue.ack(tenantId, envelope.getMsg(), ackId.getId(), msg.getClusterPartition()); | ||
225 | - } | 232 | + envelope.getMsg().getCallback().onSuccess(); |
226 | } | 233 | } |
227 | } | 234 | } |
228 | 235 | ||
229 | void onTellNext(RuleNodeToRuleChainTellNextMsg envelope) { | 236 | void onTellNext(RuleNodeToRuleChainTellNextMsg envelope) { |
230 | - checkActive(); | ||
231 | - TbMsg msg = envelope.getMsg(); | ||
232 | - EntityId originatorEntityId = msg.getOriginator(); | ||
233 | - Optional<ServerAddress> address = systemContext.getRoutingService().resolveById(originatorEntityId); | 237 | + onTellNext(envelope.getMsg(), envelope.getOriginator(), envelope.getRelationTypes(), envelope.getFailureMessage()); |
238 | + } | ||
234 | 239 | ||
235 | - if (address.isPresent()) { | ||
236 | - onRemoteTellNext(address.get(), envelope); | ||
237 | - } else { | ||
238 | - onLocalTellNext(envelope); | 240 | + private void onTellNext(TbMsg msg, RuleNodeId originatorNodeId, Set<String> relationTypes, String failureMessage) { |
241 | + try { | ||
242 | + checkActive(); | ||
243 | + EntityId entityId = msg.getOriginator(); | ||
244 | + TopicPartitionInfo tpi = systemContext.resolve(ServiceType.TB_RULE_ENGINE, tenantId, entityId); | ||
245 | + List<RuleNodeRelation> relations = nodeRoutes.get(originatorNodeId).stream() | ||
246 | + .filter(r -> contains(relationTypes, r.getType())) | ||
247 | + .collect(Collectors.toList()); | ||
248 | + int relationsCount = relations.size(); | ||
249 | + if (relationsCount == 0) { | ||
250 | + log.trace("[{}][{}][{}] No outbound relations to process", tenantId, entityId, msg.getId()); | ||
251 | + if (relationTypes.contains(TbRelationTypes.FAILURE)) { | ||
252 | + RuleNodeCtx ruleNodeCtx = nodeActors.get(originatorNodeId); | ||
253 | + if (ruleNodeCtx != null) { | ||
254 | + msg.getCallback().onFailure(new RuleNodeException(failureMessage, ruleChainName, ruleNodeCtx.getSelf())); | ||
255 | + } else { | ||
256 | + log.debug("[{}] Failure during message processing by Rule Node [{}]. Enable and see debug events for more info", entityId, originatorNodeId.getId()); | ||
257 | + msg.getCallback().onFailure(new RuleEngineException("Failure during message processing by Rule Node [" + originatorNodeId.getId().toString() + "]")); | ||
258 | + } | ||
259 | + } else { | ||
260 | + msg.getCallback().onSuccess(); | ||
261 | + } | ||
262 | + } else if (relationsCount == 1) { | ||
263 | + for (RuleNodeRelation relation : relations) { | ||
264 | + log.trace("[{}][{}][{}] Pushing message to single target: [{}]", tenantId, entityId, msg.getId(), relation.getOut()); | ||
265 | + pushToTarget(tpi, msg, relation.getOut(), relation.getType()); | ||
266 | + } | ||
267 | + } else { | ||
268 | + MultipleTbQueueTbMsgCallbackWrapper callbackWrapper = new MultipleTbQueueTbMsgCallbackWrapper(relationsCount, msg.getCallback()); | ||
269 | + log.trace("[{}][{}][{}] Pushing message to multiple targets: [{}]", tenantId, entityId, msg.getId(), relations); | ||
270 | + for (RuleNodeRelation relation : relations) { | ||
271 | + EntityId target = relation.getOut(); | ||
272 | + putToQueue(tpi, msg, callbackWrapper, target); | ||
273 | + } | ||
274 | + } | ||
275 | + } catch (Exception e) { | ||
276 | + msg.getCallback().onFailure(new RuleEngineException("onTellNext - " + e.getMessage())); | ||
239 | } | 277 | } |
240 | } | 278 | } |
241 | 279 | ||
242 | - private void onRemoteTellNext(ServerAddress serverAddress, RuleNodeToRuleChainTellNextMsg envelope) { | ||
243 | - TbMsg msg = envelope.getMsg(); | ||
244 | - log.debug("Forwarding [{}] msg to remote server [{}] due to changed originator id: [{}]", msg.getId(), serverAddress, msg.getOriginator()); | ||
245 | - envelope = new RemoteToRuleChainTellNextMsg(envelope, tenantId, entityId); | ||
246 | - systemContext.getRpcService().tell(systemContext.getEncodingService().convertToProtoDataMessage(serverAddress, envelope)); | 280 | + private void putToQueue(TopicPartitionInfo tpi, TbMsg msg, TbQueueCallback callbackWrapper, EntityId target) { |
281 | + switch (target.getEntityType()) { | ||
282 | + case RULE_NODE: | ||
283 | + putToQueue(tpi, msg.copyWithRuleNodeId(entityId, new RuleNodeId(target.getId())), callbackWrapper); | ||
284 | + break; | ||
285 | + case RULE_CHAIN: | ||
286 | + putToQueue(tpi, msg.copyWithRuleChainId(new RuleChainId(target.getId())), callbackWrapper); | ||
287 | + break; | ||
288 | + } | ||
247 | } | 289 | } |
248 | 290 | ||
249 | - private void onLocalTellNext(RuleNodeToRuleChainTellNextMsg envelope) { | ||
250 | - TbMsg msg = envelope.getMsg(); | ||
251 | - RuleNodeId originatorNodeId = envelope.getOriginator(); | ||
252 | - List<RuleNodeRelation> relations = nodeRoutes.get(originatorNodeId).stream() | ||
253 | - .filter(r -> contains(envelope.getRelationTypes(), r.getType())) | ||
254 | - .collect(Collectors.toList()); | ||
255 | - int relationsCount = relations.size(); | ||
256 | - EntityId ackId = msg.getRuleNodeId() != null ? msg.getRuleNodeId() : msg.getRuleChainId(); | ||
257 | - if (relationsCount == 0) { | ||
258 | - log.trace("[{}][{}][{}] No outbound relations to process", tenantId, entityId, msg.getId()); | ||
259 | - if (ackId != null) { | ||
260 | -// TODO: Ack this message in Kafka | ||
261 | -// queue.ack(tenantId, msg, ackId.getId(), msg.getClusterPartition()); | ||
262 | - } | ||
263 | - } else if (relationsCount == 1) { | ||
264 | - for (RuleNodeRelation relation : relations) { | ||
265 | - log.trace("[{}][{}][{}] Pushing message to single target: [{}]", tenantId, entityId, msg.getId(), relation.getOut()); | ||
266 | - pushToTarget(msg, relation.getOut(), relation.getType()); | 291 | + private void pushToTarget(TopicPartitionInfo tpi, TbMsg msg, EntityId target, String fromRelationType) { |
292 | + if (tpi.isMyPartition()) { | ||
293 | + switch (target.getEntityType()) { | ||
294 | + case RULE_NODE: | ||
295 | + pushMsgToNode(nodeActors.get(new RuleNodeId(target.getId())), msg, fromRelationType); | ||
296 | + break; | ||
297 | + case RULE_CHAIN: | ||
298 | + parent.tell(new RuleChainToRuleChainMsg(new RuleChainId(target.getId()), entityId, msg, fromRelationType), self); | ||
299 | + break; | ||
267 | } | 300 | } |
268 | } else { | 301 | } else { |
269 | - for (RuleNodeRelation relation : relations) { | ||
270 | - EntityId target = relation.getOut(); | ||
271 | - log.trace("[{}][{}][{}] Pushing message to multiple targets: [{}]", tenantId, entityId, msg.getId(), relation.getOut()); | ||
272 | - switch (target.getEntityType()) { | ||
273 | - case RULE_NODE: | ||
274 | - enqueueAndForwardMsgCopyToNode(msg, target, relation.getType()); | ||
275 | - break; | ||
276 | - case RULE_CHAIN: | ||
277 | - enqueueAndForwardMsgCopyToChain(msg, target, relation.getType()); | ||
278 | - break; | ||
279 | - } | ||
280 | - } | ||
281 | - //TODO: Ideally this should happen in async way when all targets confirm that the copied messages are successfully written to corresponding target queues. | ||
282 | - if (ackId != null) { | ||
283 | -// TODO: Ack this message in Kafka | ||
284 | -// queue.ack(tenantId, msg, ackId.getId(), msg.getClusterPartition()); | ||
285 | - } | 302 | + putToQueue(tpi, msg, new TbQueueTbMsgCallbackWrapper(msg.getCallback()), target); |
286 | } | 303 | } |
287 | } | 304 | } |
288 | 305 | ||
306 | + private void putToQueue(TopicPartitionInfo tpi, TbMsg newMsg, TbQueueCallback callbackWrapper) { | ||
307 | + ToRuleEngineMsg toQueueMsg = ToRuleEngineMsg.newBuilder() | ||
308 | + .setTenantIdMSB(tenantId.getId().getMostSignificantBits()) | ||
309 | + .setTenantIdLSB(tenantId.getId().getLeastSignificantBits()) | ||
310 | + .setTbMsg(TbMsg.toByteString(newMsg)) | ||
311 | + .build(); | ||
312 | + clusterService.pushMsgToRuleEngine(tpi, newMsg.getId(), toQueueMsg, callbackWrapper); | ||
313 | + } | ||
314 | + | ||
289 | private boolean contains(Set<String> relationTypes, String type) { | 315 | private boolean contains(Set<String> relationTypes, String type) { |
290 | if (relationTypes == null) { | 316 | if (relationTypes == null) { |
291 | return true; | 317 | return true; |
@@ -298,38 +324,13 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh | @@ -298,38 +324,13 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh | ||
298 | return false; | 324 | return false; |
299 | } | 325 | } |
300 | 326 | ||
301 | - private void enqueueAndForwardMsgCopyToChain(TbMsg msg, EntityId target, String fromRelationType) { | ||
302 | - RuleChainId targetRCId = new RuleChainId(target.getId()); | ||
303 | - TbMsg copyMsg = msg.copy(UUIDs.timeBased(), targetRCId, null, DEFAULT_CLUSTER_PARTITION); | ||
304 | - parent.tell(new RuleChainToRuleChainMsg(new RuleChainId(target.getId()), entityId, copyMsg, fromRelationType, true), self); | ||
305 | - } | ||
306 | - | ||
307 | - private void enqueueAndForwardMsgCopyToNode(TbMsg msg, EntityId target, String fromRelationType) { | ||
308 | - RuleNodeId targetId = new RuleNodeId(target.getId()); | ||
309 | - RuleNodeCtx targetNodeCtx = nodeActors.get(targetId); | ||
310 | - TbMsg copy = msg.copy(UUIDs.timeBased(), entityId, targetId, DEFAULT_CLUSTER_PARTITION); | ||
311 | - pushMsgToNode(targetNodeCtx, copy, fromRelationType); | ||
312 | - } | ||
313 | - | ||
314 | - private void pushToTarget(TbMsg msg, EntityId target, String fromRelationType) { | ||
315 | - switch (target.getEntityType()) { | ||
316 | - case RULE_NODE: | ||
317 | - pushMsgToNode(nodeActors.get(new RuleNodeId(target.getId())), msg, fromRelationType); | ||
318 | - break; | ||
319 | - case RULE_CHAIN: | ||
320 | - parent.tell(new RuleChainToRuleChainMsg(new RuleChainId(target.getId()), entityId, msg, fromRelationType, false), self); | ||
321 | - break; | ||
322 | - } | ||
323 | - } | ||
324 | - | ||
325 | private void pushMsgToNode(RuleNodeCtx nodeCtx, TbMsg msg, String fromRelationType) { | 327 | private void pushMsgToNode(RuleNodeCtx nodeCtx, TbMsg msg, String fromRelationType) { |
326 | if (nodeCtx != null) { | 328 | if (nodeCtx != null) { |
327 | nodeCtx.getSelfActor().tell(new RuleChainToRuleNodeMsg(new DefaultTbContext(systemContext, nodeCtx), msg, fromRelationType), self); | 329 | nodeCtx.getSelfActor().tell(new RuleChainToRuleNodeMsg(new DefaultTbContext(systemContext, nodeCtx), msg, fromRelationType), self); |
330 | + } else { | ||
331 | + log.error("[{}][{}] RuleNodeCtx is empty", entityId, ruleChainName); | ||
332 | + msg.getCallback().onFailure(new RuleEngineException("Rule Node CTX is empty")); | ||
328 | } | 333 | } |
329 | } | 334 | } |
330 | 335 | ||
331 | - private TbMsg enrichWithRuleChainId(TbMsg tbMsg) { | ||
332 | - // We don't put firstNodeId because it may change over time; | ||
333 | - return new TbMsg(tbMsg.getId(), tbMsg.getType(), tbMsg.getOriginator(), tbMsg.getMetaData().copy(), tbMsg.getData(), entityId, null, systemContext.getQueuePartitionId()); | ||
334 | - } | ||
335 | } | 336 | } |
@@ -15,43 +15,89 @@ | @@ -15,43 +15,89 @@ | ||
15 | */ | 15 | */ |
16 | package org.thingsboard.server.actors.ruleChain; | 16 | package org.thingsboard.server.actors.ruleChain; |
17 | 17 | ||
18 | +import akka.actor.ActorContext; | ||
18 | import akka.actor.ActorRef; | 19 | import akka.actor.ActorRef; |
20 | +import akka.actor.Props; | ||
21 | +import com.google.common.collect.BiMap; | ||
22 | +import com.google.common.collect.HashBiMap; | ||
23 | +import lombok.Getter; | ||
19 | import org.thingsboard.server.actors.ActorSystemContext; | 24 | import org.thingsboard.server.actors.ActorSystemContext; |
20 | import org.thingsboard.server.actors.service.ContextAwareActor; | 25 | import org.thingsboard.server.actors.service.ContextAwareActor; |
21 | -import org.thingsboard.server.actors.shared.rulechain.RuleChainManager; | 26 | +import org.thingsboard.server.actors.service.DefaultActorService; |
27 | +import org.thingsboard.server.common.data.EntityType; | ||
22 | import org.thingsboard.server.common.data.id.EntityId; | 28 | import org.thingsboard.server.common.data.id.EntityId; |
23 | import org.thingsboard.server.common.data.id.RuleChainId; | 29 | import org.thingsboard.server.common.data.id.RuleChainId; |
30 | +import org.thingsboard.server.common.data.id.TenantId; | ||
31 | +import org.thingsboard.server.common.data.page.PageDataIterable; | ||
32 | +import org.thingsboard.server.common.data.rule.RuleChain; | ||
24 | import org.thingsboard.server.dao.rule.RuleChainService; | 33 | import org.thingsboard.server.dao.rule.RuleChainService; |
25 | 34 | ||
35 | +import java.util.function.Function; | ||
36 | + | ||
26 | /** | 37 | /** |
27 | * Created by ashvayka on 15.03.18. | 38 | * Created by ashvayka on 15.03.18. |
28 | */ | 39 | */ |
29 | public abstract class RuleChainManagerActor extends ContextAwareActor { | 40 | public abstract class RuleChainManagerActor extends ContextAwareActor { |
30 | 41 | ||
31 | - protected final RuleChainManager ruleChainManager; | ||
32 | - protected final RuleChainService ruleChainService; | 42 | + protected final TenantId tenantId; |
43 | + private final RuleChainService ruleChainService; | ||
44 | + private final BiMap<RuleChainId, ActorRef> actors; | ||
45 | + @Getter | ||
46 | + protected RuleChain rootChain; | ||
47 | + @Getter | ||
48 | + protected ActorRef rootChainActor; | ||
33 | 49 | ||
34 | - public RuleChainManagerActor(ActorSystemContext systemContext, RuleChainManager ruleChainManager) { | 50 | + public RuleChainManagerActor(ActorSystemContext systemContext, TenantId tenantId) { |
35 | super(systemContext); | 51 | super(systemContext); |
36 | - this.ruleChainManager = ruleChainManager; | 52 | + this.tenantId = tenantId; |
53 | + this.actors = HashBiMap.create(); | ||
37 | this.ruleChainService = systemContext.getRuleChainService(); | 54 | this.ruleChainService = systemContext.getRuleChainService(); |
38 | } | 55 | } |
39 | 56 | ||
40 | protected void initRuleChains() { | 57 | protected void initRuleChains() { |
41 | - ruleChainManager.init(this.context()); | 58 | + for (RuleChain ruleChain : new PageDataIterable<>(link -> ruleChainService.findTenantRuleChains(tenantId, link), ContextAwareActor.ENTITY_PACK_LIMIT)) { |
59 | + RuleChainId ruleChainId = ruleChain.getId(); | ||
60 | + log.debug("[{}|{}] Creating rule chain actor", ruleChainId.getEntityType(), ruleChain.getId()); | ||
61 | + //TODO: remove this cast making UUIDBased subclass of EntityId an interface and vice versa. | ||
62 | + ActorRef actorRef = getOrCreateActor(this.context(), ruleChainId, id -> ruleChain); | ||
63 | + visit(ruleChain, actorRef); | ||
64 | + log.debug("[{}|{}] Rule Chain actor created.", ruleChainId.getEntityType(), ruleChainId.getId()); | ||
65 | + } | ||
66 | + } | ||
67 | + | ||
68 | + protected void visit(RuleChain entity, ActorRef actorRef) { | ||
69 | + if (entity != null && entity.isRoot()) { | ||
70 | + rootChain = entity; | ||
71 | + rootChainActor = actorRef; | ||
72 | + } | ||
73 | + } | ||
74 | + | ||
75 | + public ActorRef getOrCreateActor(akka.actor.ActorContext context, RuleChainId ruleChainId) { | ||
76 | + return getOrCreateActor(context, ruleChainId, eId -> ruleChainService.findRuleChainById(TenantId.SYS_TENANT_ID, eId)); | ||
77 | + } | ||
78 | + | ||
79 | + public ActorRef getOrCreateActor(akka.actor.ActorContext context, RuleChainId ruleChainId, Function<RuleChainId, RuleChain> provider) { | ||
80 | + return actors.computeIfAbsent(ruleChainId, eId -> { | ||
81 | + RuleChain ruleChain = provider.apply(eId); | ||
82 | + return context.actorOf(Props.create(new RuleChainActor.ActorCreator(systemContext, tenantId, ruleChain)) | ||
83 | + .withDispatcher(DefaultActorService.TENANT_RULE_DISPATCHER_NAME), eId.toString()); | ||
84 | + }); | ||
42 | } | 85 | } |
43 | 86 | ||
44 | protected ActorRef getEntityActorRef(EntityId entityId) { | 87 | protected ActorRef getEntityActorRef(EntityId entityId) { |
45 | ActorRef target = null; | 88 | ActorRef target = null; |
46 | - switch (entityId.getEntityType()) { | ||
47 | - case RULE_CHAIN: | ||
48 | - target = ruleChainManager.getOrCreateActor(this.context(), (RuleChainId) entityId); | ||
49 | - break; | 89 | + if (entityId.getEntityType() == EntityType.RULE_CHAIN) { |
90 | + target = getOrCreateActor(this.context(), (RuleChainId) entityId); | ||
50 | } | 91 | } |
51 | return target; | 92 | return target; |
52 | } | 93 | } |
53 | 94 | ||
54 | protected void broadcast(Object msg) { | 95 | protected void broadcast(Object msg) { |
55 | - ruleChainManager.broadcast(msg); | 96 | + actors.values().forEach(actorRef -> actorRef.tell(msg, ActorRef.noSender())); |
56 | } | 97 | } |
98 | + | ||
99 | + public ActorRef get(RuleChainId id) { | ||
100 | + return actors.get(id); | ||
101 | + } | ||
102 | + | ||
57 | } | 103 | } |
@@ -32,7 +32,6 @@ public final class RuleChainToRuleChainMsg implements TbActorMsg, RuleChainAware | @@ -32,7 +32,6 @@ public final class RuleChainToRuleChainMsg implements TbActorMsg, RuleChainAware | ||
32 | private final RuleChainId source; | 32 | private final RuleChainId source; |
33 | private final TbMsg msg; | 33 | private final TbMsg msg; |
34 | private final String fromRelationType; | 34 | private final String fromRelationType; |
35 | - private final boolean enqueue; | ||
36 | 35 | ||
37 | @Override | 36 | @Override |
38 | public RuleChainId getRuleChainId() { | 37 | public RuleChainId getRuleChainId() { |
@@ -23,6 +23,7 @@ import org.thingsboard.server.common.data.id.RuleNodeId; | @@ -23,6 +23,7 @@ import org.thingsboard.server.common.data.id.RuleNodeId; | ||
23 | import org.thingsboard.server.common.data.id.TenantId; | 23 | import org.thingsboard.server.common.data.id.TenantId; |
24 | import org.thingsboard.server.common.msg.TbActorMsg; | 24 | import org.thingsboard.server.common.msg.TbActorMsg; |
25 | import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; | 25 | import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; |
26 | +import org.thingsboard.server.common.msg.queue.PartitionChangeMsg; | ||
26 | 27 | ||
27 | public class RuleNodeActor extends ComponentActor<RuleNodeId, RuleNodeActorMessageProcessor> { | 28 | public class RuleNodeActor extends ComponentActor<RuleNodeId, RuleNodeActorMessageProcessor> { |
28 | 29 | ||
@@ -53,6 +54,9 @@ public class RuleNodeActor extends ComponentActor<RuleNodeId, RuleNodeActorMessa | @@ -53,6 +54,9 @@ public class RuleNodeActor extends ComponentActor<RuleNodeId, RuleNodeActorMessa | ||
53 | case STATS_PERSIST_TICK_MSG: | 54 | case STATS_PERSIST_TICK_MSG: |
54 | onStatsPersistTick(id); | 55 | onStatsPersistTick(id); |
55 | break; | 56 | break; |
57 | + case PARTITION_CHANGE_MSG: | ||
58 | + onClusterEventMsg((PartitionChangeMsg) msg); | ||
59 | + break; | ||
56 | default: | 60 | default: |
57 | return false; | 61 | return false; |
58 | } | 62 | } |
application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeActorMessageProcessor.java
@@ -27,7 +27,7 @@ import org.thingsboard.server.common.data.id.RuleNodeId; | @@ -27,7 +27,7 @@ import org.thingsboard.server.common.data.id.RuleNodeId; | ||
27 | import org.thingsboard.server.common.data.id.TenantId; | 27 | import org.thingsboard.server.common.data.id.TenantId; |
28 | import org.thingsboard.server.common.data.plugin.ComponentLifecycleState; | 28 | import org.thingsboard.server.common.data.plugin.ComponentLifecycleState; |
29 | import org.thingsboard.server.common.data.rule.RuleNode; | 29 | import org.thingsboard.server.common.data.rule.RuleNode; |
30 | -import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; | 30 | +import org.thingsboard.server.common.msg.queue.PartitionChangeMsg; |
31 | import org.thingsboard.server.dao.rule.RuleChainService; | 31 | import org.thingsboard.server.dao.rule.RuleChainService; |
32 | 32 | ||
33 | /** | 33 | /** |
@@ -40,7 +40,7 @@ public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNod | @@ -40,7 +40,7 @@ public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNod | ||
40 | private final RuleChainService service; | 40 | private final RuleChainService service; |
41 | private RuleNode ruleNode; | 41 | private RuleNode ruleNode; |
42 | private TbNode tbNode; | 42 | private TbNode tbNode; |
43 | - private TbContext defaultCtx; | 43 | + private DefaultTbContext defaultCtx; |
44 | 44 | ||
45 | RuleNodeActorMessageProcessor(TenantId tenantId, RuleChainId ruleChainId, RuleNodeId ruleNodeId, ActorSystemContext systemContext | 45 | RuleNodeActorMessageProcessor(TenantId tenantId, RuleChainId ruleChainId, RuleNodeId ruleNodeId, ActorSystemContext systemContext |
46 | , ActorRef parent, ActorRef self) { | 46 | , ActorRef parent, ActorRef self) { |
@@ -84,9 +84,9 @@ public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNod | @@ -84,9 +84,9 @@ public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNod | ||
84 | } | 84 | } |
85 | 85 | ||
86 | @Override | 86 | @Override |
87 | - public void onClusterEventMsg(ClusterEventMsg msg) { | 87 | + public void onPartitionChangeMsg(PartitionChangeMsg msg) { |
88 | if (tbNode != null) { | 88 | if (tbNode != null) { |
89 | - tbNode.onClusterEventMsg(defaultCtx, msg); | 89 | + tbNode.onPartitionChangeMsg(defaultCtx, msg); |
90 | } | 90 | } |
91 | } | 91 | } |
92 | 92 |
@@ -34,6 +34,7 @@ class RuleNodeToRuleChainTellNextMsg implements TbActorMsg, Serializable { | @@ -34,6 +34,7 @@ class RuleNodeToRuleChainTellNextMsg implements TbActorMsg, Serializable { | ||
34 | private final RuleNodeId originator; | 34 | private final RuleNodeId originator; |
35 | private final Set<String> relationTypes; | 35 | private final Set<String> relationTypes; |
36 | private final TbMsg msg; | 36 | private final TbMsg msg; |
37 | + private final String failureMessage; | ||
37 | 38 | ||
38 | @Override | 39 | @Override |
39 | public MsgType getMsgType() { | 40 | public MsgType getMsgType() { |
@@ -15,24 +15,7 @@ | @@ -15,24 +15,7 @@ | ||
15 | */ | 15 | */ |
16 | package org.thingsboard.server.actors.service; | 16 | package org.thingsboard.server.actors.service; |
17 | 17 | ||
18 | -import org.thingsboard.server.common.data.id.DeviceId; | ||
19 | -import org.thingsboard.server.common.data.id.EntityId; | ||
20 | -import org.thingsboard.server.common.data.id.TenantId; | ||
21 | -import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; | ||
22 | -import org.thingsboard.server.common.msg.cluster.SendToClusterMsg; | ||
23 | -import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg; | ||
24 | -import org.thingsboard.server.common.transport.SessionMsgProcessor; | ||
25 | -import org.thingsboard.server.service.cluster.discovery.DiscoveryServiceListener; | ||
26 | -import org.thingsboard.server.service.cluster.rpc.RpcMsgListener; | 18 | +public interface ActorService { |
27 | 19 | ||
28 | -public interface ActorService extends SessionMsgProcessor, RpcMsgListener, DiscoveryServiceListener { | ||
29 | - | ||
30 | - void onEntityStateChange(TenantId tenantId, EntityId entityId, ComponentLifecycleEvent state); | ||
31 | - | ||
32 | - void onMsg(SendToClusterMsg msg); | ||
33 | - | ||
34 | - void onCredentialsUpdate(TenantId tenantId, DeviceId deviceId); | ||
35 | - | ||
36 | - void onDeviceNameOrTypeUpdate(TenantId tenantId, DeviceId deviceId, String deviceName, String deviceType); | ||
37 | 20 | ||
38 | } | 21 | } |
@@ -22,7 +22,7 @@ import org.thingsboard.server.actors.stats.StatsPersistMsg; | @@ -22,7 +22,7 @@ import org.thingsboard.server.actors.stats.StatsPersistMsg; | ||
22 | import org.thingsboard.server.common.data.id.EntityId; | 22 | import org.thingsboard.server.common.data.id.EntityId; |
23 | import org.thingsboard.server.common.data.id.TenantId; | 23 | import org.thingsboard.server.common.data.id.TenantId; |
24 | import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; | 24 | import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; |
25 | -import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; | 25 | +import org.thingsboard.server.common.msg.queue.PartitionChangeMsg; |
26 | import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; | 26 | import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; |
27 | 27 | ||
28 | /** | 28 | /** |
@@ -115,9 +115,9 @@ public abstract class ComponentActor<T extends EntityId, P extends ComponentMsgP | @@ -115,9 +115,9 @@ public abstract class ComponentActor<T extends EntityId, P extends ComponentMsgP | ||
115 | } | 115 | } |
116 | } | 116 | } |
117 | 117 | ||
118 | - protected void onClusterEventMsg(ClusterEventMsg msg) { | 118 | + protected void onClusterEventMsg(PartitionChangeMsg msg) { |
119 | try { | 119 | try { |
120 | - processor.onClusterEventMsg(msg); | 120 | + processor.onPartitionChangeMsg(msg); |
121 | } catch (Exception e) { | 121 | } catch (Exception e) { |
122 | logAndPersist("onClusterEventMsg", e); | 122 | logAndPersist("onClusterEventMsg", e); |
123 | } | 123 | } |
@@ -16,14 +16,14 @@ | @@ -16,14 +16,14 @@ | ||
16 | package org.thingsboard.server.actors.service; | 16 | package org.thingsboard.server.actors.service; |
17 | 17 | ||
18 | import akka.actor.Terminated; | 18 | import akka.actor.Terminated; |
19 | -import akka.actor.UntypedActor; | 19 | +import akka.actor.UntypedAbstractActor; |
20 | import org.slf4j.Logger; | 20 | import org.slf4j.Logger; |
21 | import org.slf4j.LoggerFactory; | 21 | import org.slf4j.LoggerFactory; |
22 | import org.thingsboard.server.actors.ActorSystemContext; | 22 | import org.thingsboard.server.actors.ActorSystemContext; |
23 | import org.thingsboard.server.common.msg.TbActorMsg; | 23 | import org.thingsboard.server.common.msg.TbActorMsg; |
24 | 24 | ||
25 | 25 | ||
26 | -public abstract class ContextAwareActor extends UntypedActor { | 26 | +public abstract class ContextAwareActor extends UntypedAbstractActor { |
27 | 27 | ||
28 | protected final Logger log = LoggerFactory.getLogger(getClass()); | 28 | protected final Logger log = LoggerFactory.getLogger(getClass()); |
29 | 29 |
@@ -19,7 +19,6 @@ import akka.actor.ActorRef; | @@ -19,7 +19,6 @@ import akka.actor.ActorRef; | ||
19 | import akka.actor.ActorSystem; | 19 | import akka.actor.ActorSystem; |
20 | import akka.actor.Props; | 20 | import akka.actor.Props; |
21 | import akka.actor.Terminated; | 21 | import akka.actor.Terminated; |
22 | -import com.google.protobuf.ByteString; | ||
23 | import lombok.extern.slf4j.Slf4j; | 22 | import lombok.extern.slf4j.Slf4j; |
24 | import org.springframework.beans.factory.annotation.Autowired; | 23 | import org.springframework.beans.factory.annotation.Autowired; |
25 | import org.springframework.beans.factory.annotation.Value; | 24 | import org.springframework.beans.factory.annotation.Value; |
@@ -27,44 +26,20 @@ import org.springframework.boot.context.event.ApplicationReadyEvent; | @@ -27,44 +26,20 @@ import org.springframework.boot.context.event.ApplicationReadyEvent; | ||
27 | import org.springframework.context.event.EventListener; | 26 | import org.springframework.context.event.EventListener; |
28 | import org.springframework.scheduling.annotation.Scheduled; | 27 | import org.springframework.scheduling.annotation.Scheduled; |
29 | import org.springframework.stereotype.Service; | 28 | import org.springframework.stereotype.Service; |
30 | -import org.thingsboard.rule.engine.api.msg.DeviceCredentialsUpdateNotificationMsg; | ||
31 | -import org.thingsboard.rule.engine.api.msg.DeviceNameOrTypeUpdateMsg; | ||
32 | import org.thingsboard.server.actors.ActorSystemContext; | 29 | import org.thingsboard.server.actors.ActorSystemContext; |
33 | import org.thingsboard.server.actors.app.AppActor; | 30 | import org.thingsboard.server.actors.app.AppActor; |
34 | import org.thingsboard.server.actors.app.AppInitMsg; | 31 | import org.thingsboard.server.actors.app.AppInitMsg; |
35 | -import org.thingsboard.server.actors.rpc.RpcBroadcastMsg; | ||
36 | -import org.thingsboard.server.actors.rpc.RpcManagerActor; | ||
37 | -import org.thingsboard.server.actors.rpc.RpcSessionCreateRequestMsg; | ||
38 | import org.thingsboard.server.actors.stats.StatsActor; | 32 | import org.thingsboard.server.actors.stats.StatsActor; |
39 | -import org.thingsboard.server.common.data.Device; | ||
40 | -import org.thingsboard.server.common.data.id.DeviceId; | ||
41 | -import org.thingsboard.server.common.data.id.EntityId; | ||
42 | -import org.thingsboard.server.common.data.id.TenantId; | ||
43 | -import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; | ||
44 | -import org.thingsboard.server.common.msg.TbActorMsg; | ||
45 | -import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; | ||
46 | -import org.thingsboard.server.common.msg.cluster.SendToClusterMsg; | ||
47 | -import org.thingsboard.server.common.msg.cluster.ServerAddress; | ||
48 | -import org.thingsboard.server.common.msg.cluster.ToAllNodesMsg; | ||
49 | -import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; | ||
50 | -import org.thingsboard.server.gen.cluster.ClusterAPIProtos; | ||
51 | -import org.thingsboard.server.service.cluster.discovery.DiscoveryService; | ||
52 | -import org.thingsboard.server.service.cluster.discovery.ServerInstance; | ||
53 | -import org.thingsboard.server.service.cluster.rpc.ClusterRpcService; | ||
54 | -import org.thingsboard.server.service.state.DeviceStateService; | ||
55 | -import org.thingsboard.server.service.transport.RuleEngineStats; | 33 | +import org.thingsboard.server.common.msg.queue.PartitionChangeMsg; |
34 | +import org.thingsboard.server.queue.discovery.PartitionChangeEvent; | ||
56 | import scala.concurrent.Await; | 35 | import scala.concurrent.Await; |
57 | import scala.concurrent.Future; | 36 | import scala.concurrent.Future; |
58 | import scala.concurrent.duration.Duration; | 37 | import scala.concurrent.duration.Duration; |
59 | 38 | ||
60 | import javax.annotation.PostConstruct; | 39 | import javax.annotation.PostConstruct; |
61 | import javax.annotation.PreDestroy; | 40 | import javax.annotation.PreDestroy; |
62 | -import java.util.concurrent.Executors; | ||
63 | -import java.util.concurrent.ScheduledExecutorService; | ||
64 | import java.util.concurrent.atomic.AtomicInteger; | 41 | import java.util.concurrent.atomic.AtomicInteger; |
65 | 42 | ||
66 | -import static org.thingsboard.server.gen.cluster.ClusterAPIProtos.MessageType.CLUSTER_ACTOR_MESSAGE; | ||
67 | - | ||
68 | @Service | 43 | @Service |
69 | @Slf4j | 44 | @Slf4j |
70 | public class DefaultActorService implements ActorService { | 45 | public class DefaultActorService implements ActorService { |
@@ -75,26 +50,14 @@ public class DefaultActorService implements ActorService { | @@ -75,26 +50,14 @@ public class DefaultActorService implements ActorService { | ||
75 | public static final String CORE_DISPATCHER_NAME = "core-dispatcher"; | 50 | public static final String CORE_DISPATCHER_NAME = "core-dispatcher"; |
76 | public static final String SYSTEM_RULE_DISPATCHER_NAME = "system-rule-dispatcher"; | 51 | public static final String SYSTEM_RULE_DISPATCHER_NAME = "system-rule-dispatcher"; |
77 | public static final String TENANT_RULE_DISPATCHER_NAME = "rule-dispatcher"; | 52 | public static final String TENANT_RULE_DISPATCHER_NAME = "rule-dispatcher"; |
78 | - public static final String RPC_DISPATCHER_NAME = "rpc-dispatcher"; | ||
79 | 53 | ||
80 | @Autowired | 54 | @Autowired |
81 | private ActorSystemContext actorContext; | 55 | private ActorSystemContext actorContext; |
82 | 56 | ||
83 | - @Autowired | ||
84 | - private ClusterRpcService rpcService; | ||
85 | - | ||
86 | - @Autowired | ||
87 | - private DiscoveryService discoveryService; | ||
88 | - | ||
89 | - @Autowired | ||
90 | - private DeviceStateService deviceStateService; | ||
91 | - | ||
92 | private ActorSystem system; | 57 | private ActorSystem system; |
93 | 58 | ||
94 | private ActorRef appActor; | 59 | private ActorRef appActor; |
95 | 60 | ||
96 | - private ActorRef rpcManagerActor; | ||
97 | - | ||
98 | @PostConstruct | 61 | @PostConstruct |
99 | public void initActorSystem() { | 62 | public void initActorSystem() { |
100 | log.info("Initializing Actor system."); | 63 | log.info("Initializing Actor system."); |
@@ -105,13 +68,9 @@ public class DefaultActorService implements ActorService { | @@ -105,13 +68,9 @@ public class DefaultActorService implements ActorService { | ||
105 | appActor = system.actorOf(Props.create(new AppActor.ActorCreator(actorContext)).withDispatcher(APP_DISPATCHER_NAME), "appActor"); | 68 | appActor = system.actorOf(Props.create(new AppActor.ActorCreator(actorContext)).withDispatcher(APP_DISPATCHER_NAME), "appActor"); |
106 | actorContext.setAppActor(appActor); | 69 | actorContext.setAppActor(appActor); |
107 | 70 | ||
108 | - rpcManagerActor = system.actorOf(Props.create(new RpcManagerActor.ActorCreator(actorContext)).withDispatcher(CORE_DISPATCHER_NAME), | ||
109 | - "rpcManagerActor"); | ||
110 | - | ||
111 | ActorRef statsActor = system.actorOf(Props.create(new StatsActor.ActorCreator(actorContext)).withDispatcher(CORE_DISPATCHER_NAME), "statsActor"); | 71 | ActorRef statsActor = system.actorOf(Props.create(new StatsActor.ActorCreator(actorContext)).withDispatcher(CORE_DISPATCHER_NAME), "statsActor"); |
112 | actorContext.setStatsActor(statsActor); | 72 | actorContext.setStatsActor(statsActor); |
113 | 73 | ||
114 | - rpcService.init(this); | ||
115 | log.info("Actor system initialized."); | 74 | log.info("Actor system initialized."); |
116 | } | 75 | } |
117 | 76 | ||
@@ -121,6 +80,12 @@ public class DefaultActorService implements ActorService { | @@ -121,6 +80,12 @@ public class DefaultActorService implements ActorService { | ||
121 | appActor.tell(new AppInitMsg(), ActorRef.noSender()); | 80 | appActor.tell(new AppInitMsg(), ActorRef.noSender()); |
122 | } | 81 | } |
123 | 82 | ||
83 | + @EventListener(PartitionChangeEvent.class) | ||
84 | + public void onApplicationEvent(PartitionChangeEvent partitionChangeEvent) { | ||
85 | + log.info("Received partition change event."); | ||
86 | + this.appActor.tell(new PartitionChangeMsg(partitionChangeEvent.getServiceQueueKey(), partitionChangeEvent.getPartitions()), ActorRef.noSender()); | ||
87 | + } | ||
88 | + | ||
124 | @PreDestroy | 89 | @PreDestroy |
125 | public void stopActorSystem() { | 90 | public void stopActorSystem() { |
126 | Future<Terminated> status = system.terminate(); | 91 | Future<Terminated> status = system.terminate(); |
@@ -132,157 +97,4 @@ public class DefaultActorService implements ActorService { | @@ -132,157 +97,4 @@ public class DefaultActorService implements ActorService { | ||
132 | } | 97 | } |
133 | } | 98 | } |
134 | 99 | ||
135 | - @Override | ||
136 | - public void onMsg(SendToClusterMsg msg) { | ||
137 | - appActor.tell(msg, ActorRef.noSender()); | ||
138 | - } | ||
139 | - | ||
140 | - @Override | ||
141 | - public void onServerAdded(ServerInstance server) { | ||
142 | - log.trace("Processing onServerAdded msg: {}", server); | ||
143 | - broadcast(new ClusterEventMsg(server.getServerAddress(), true)); | ||
144 | - } | ||
145 | - | ||
146 | - @Override | ||
147 | - public void onServerUpdated(ServerInstance server) { | ||
148 | - //Do nothing | ||
149 | - } | ||
150 | - | ||
151 | - @Override | ||
152 | - public void onServerRemoved(ServerInstance server) { | ||
153 | - log.trace("Processing onServerRemoved msg: {}", server); | ||
154 | - broadcast(new ClusterEventMsg(server.getServerAddress(), false)); | ||
155 | - } | ||
156 | - | ||
157 | - @Override | ||
158 | - public void onEntityStateChange(TenantId tenantId, EntityId entityId, ComponentLifecycleEvent state) { | ||
159 | - log.trace("[{}] Processing {} state change event: {}", tenantId, entityId.getEntityType(), state); | ||
160 | - broadcast(new ComponentLifecycleMsg(tenantId, entityId, state)); | ||
161 | - } | ||
162 | - | ||
163 | - @Override | ||
164 | - public void onCredentialsUpdate(TenantId tenantId, DeviceId deviceId) { | ||
165 | - DeviceCredentialsUpdateNotificationMsg msg = new DeviceCredentialsUpdateNotificationMsg(tenantId, deviceId); | ||
166 | - appActor.tell(new SendToClusterMsg(deviceId, msg), ActorRef.noSender()); | ||
167 | - } | ||
168 | - | ||
169 | - @Override | ||
170 | - public void onDeviceNameOrTypeUpdate(TenantId tenantId, DeviceId deviceId, String deviceName, String deviceType) { | ||
171 | - log.trace("[{}] Processing onDeviceNameOrTypeUpdate event, deviceName: {}, deviceType: {}", deviceId, deviceName, deviceType); | ||
172 | - DeviceNameOrTypeUpdateMsg msg = new DeviceNameOrTypeUpdateMsg(tenantId, deviceId, deviceName, deviceType); | ||
173 | - appActor.tell(new SendToClusterMsg(deviceId, msg), ActorRef.noSender()); | ||
174 | - } | ||
175 | - | ||
176 | - public void broadcast(ToAllNodesMsg msg) { | ||
177 | - actorContext.getEncodingService().encode(msg); | ||
178 | - rpcService.broadcast(new RpcBroadcastMsg(ClusterAPIProtos.ClusterMessage | ||
179 | - .newBuilder() | ||
180 | - .setPayload(ByteString | ||
181 | - .copyFrom(actorContext.getEncodingService().encode(msg))) | ||
182 | - .setMessageType(CLUSTER_ACTOR_MESSAGE) | ||
183 | - .build())); | ||
184 | - appActor.tell(msg, ActorRef.noSender()); | ||
185 | - } | ||
186 | - | ||
187 | - private void broadcast(ClusterEventMsg msg) { | ||
188 | - this.appActor.tell(msg, ActorRef.noSender()); | ||
189 | - this.rpcManagerActor.tell(msg, ActorRef.noSender()); | ||
190 | - } | ||
191 | - | ||
192 | - @Value("${cluster.stats.enabled:false}") | ||
193 | - private boolean statsEnabled; | ||
194 | - | ||
195 | - private final AtomicInteger sentClusterMsgs = new AtomicInteger(0); | ||
196 | - private final AtomicInteger receivedClusterMsgs = new AtomicInteger(0); | ||
197 | - | ||
198 | - | ||
199 | - @Scheduled(fixedDelayString = "${cluster.stats.print_interval_ms}") | ||
200 | - public void printStats() { | ||
201 | - if (statsEnabled) { | ||
202 | - int sent = sentClusterMsgs.getAndSet(0); | ||
203 | - int received = receivedClusterMsgs.getAndSet(0); | ||
204 | - if (sent > 0 || received > 0) { | ||
205 | - log.info("Cluster msgs sent [{}] received [{}]", sent, received); | ||
206 | - } | ||
207 | - } | ||
208 | - } | ||
209 | - | ||
210 | - @Override | ||
211 | - public void onReceivedMsg(ServerAddress source, ClusterAPIProtos.ClusterMessage msg) { | ||
212 | - if (statsEnabled) { | ||
213 | - receivedClusterMsgs.incrementAndGet(); | ||
214 | - } | ||
215 | - ServerAddress serverAddress = new ServerAddress(source.getHost(), source.getPort(), source.getServerType()); | ||
216 | - if (log.isDebugEnabled()) { | ||
217 | - log.info("Received msg [{}] from [{}]", msg.getMessageType().name(), serverAddress); | ||
218 | - log.info("MSG: {}", msg); | ||
219 | - } | ||
220 | - switch (msg.getMessageType()) { | ||
221 | - case CLUSTER_ACTOR_MESSAGE: | ||
222 | - java.util.Optional<TbActorMsg> decodedMsg = actorContext.getEncodingService() | ||
223 | - .decode(msg.getPayload().toByteArray()); | ||
224 | - if (decodedMsg.isPresent()) { | ||
225 | - appActor.tell(decodedMsg.get(), ActorRef.noSender()); | ||
226 | - } else { | ||
227 | - log.error("Error during decoding cluster proto message"); | ||
228 | - } | ||
229 | - break; | ||
230 | - case TO_ALL_NODES_MSG: | ||
231 | - //TODO | ||
232 | - break; | ||
233 | - case CLUSTER_TELEMETRY_SUBSCRIPTION_CREATE_MESSAGE: | ||
234 | - actorContext.getTsSubService().onNewRemoteSubscription(serverAddress, msg.getPayload().toByteArray()); | ||
235 | - break; | ||
236 | - case CLUSTER_TELEMETRY_SUBSCRIPTION_UPDATE_MESSAGE: | ||
237 | - actorContext.getTsSubService().onRemoteSubscriptionUpdate(serverAddress, msg.getPayload().toByteArray()); | ||
238 | - break; | ||
239 | - case CLUSTER_TELEMETRY_SUBSCRIPTION_CLOSE_MESSAGE: | ||
240 | - actorContext.getTsSubService().onRemoteSubscriptionClose(serverAddress, msg.getPayload().toByteArray()); | ||
241 | - break; | ||
242 | - case CLUSTER_TELEMETRY_SESSION_CLOSE_MESSAGE: | ||
243 | - actorContext.getTsSubService().onRemoteSessionClose(serverAddress, msg.getPayload().toByteArray()); | ||
244 | - break; | ||
245 | - case CLUSTER_TELEMETRY_ATTR_UPDATE_MESSAGE: | ||
246 | - actorContext.getTsSubService().onRemoteAttributesUpdate(serverAddress, msg.getPayload().toByteArray()); | ||
247 | - break; | ||
248 | - case CLUSTER_TELEMETRY_TS_UPDATE_MESSAGE: | ||
249 | - actorContext.getTsSubService().onRemoteTsUpdate(serverAddress, msg.getPayload().toByteArray()); | ||
250 | - break; | ||
251 | - case CLUSTER_RPC_FROM_DEVICE_RESPONSE_MESSAGE: | ||
252 | - actorContext.getDeviceRpcService().processResponseToServerSideRPCRequestFromRemoteServer(serverAddress, msg.getPayload().toByteArray()); | ||
253 | - break; | ||
254 | - case CLUSTER_DEVICE_STATE_SERVICE_MESSAGE: | ||
255 | - actorContext.getDeviceStateService().onRemoteMsg(serverAddress, msg.getPayload().toByteArray()); | ||
256 | - break; | ||
257 | - case CLUSTER_TRANSACTION_SERVICE_MESSAGE: | ||
258 | - actorContext.getRuleChainTransactionService().onRemoteTransactionMsg(serverAddress, msg.getPayload().toByteArray()); | ||
259 | - break; | ||
260 | - } | ||
261 | - } | ||
262 | - | ||
263 | - @Override | ||
264 | - public void onSendMsg(ClusterAPIProtos.ClusterMessage msg) { | ||
265 | - if (statsEnabled) { | ||
266 | - sentClusterMsgs.incrementAndGet(); | ||
267 | - } | ||
268 | - rpcManagerActor.tell(msg, ActorRef.noSender()); | ||
269 | - } | ||
270 | - | ||
271 | - @Override | ||
272 | - public void onRpcSessionCreateRequestMsg(RpcSessionCreateRequestMsg msg) { | ||
273 | - if (statsEnabled) { | ||
274 | - sentClusterMsgs.incrementAndGet(); | ||
275 | - } | ||
276 | - rpcManagerActor.tell(msg, ActorRef.noSender()); | ||
277 | - } | ||
278 | - | ||
279 | - @Override | ||
280 | - public void onBroadcastMsg(RpcBroadcastMsg msg) { | ||
281 | - rpcManagerActor.tell(msg, ActorRef.noSender()); | ||
282 | - } | ||
283 | - | ||
284 | - @Override | ||
285 | - public void onDeviceAdded(Device device) { | ||
286 | - deviceStateService.onDeviceAdded(device); | ||
287 | - } | ||
288 | } | 100 | } |
@@ -16,20 +16,13 @@ | @@ -16,20 +16,13 @@ | ||
16 | package org.thingsboard.server.actors.shared; | 16 | package org.thingsboard.server.actors.shared; |
17 | 17 | ||
18 | import akka.actor.ActorContext; | 18 | import akka.actor.ActorContext; |
19 | -import akka.event.LoggingAdapter; | ||
20 | -import com.google.common.util.concurrent.FutureCallback; | ||
21 | -import com.google.common.util.concurrent.Futures; | ||
22 | import lombok.extern.slf4j.Slf4j; | 19 | import lombok.extern.slf4j.Slf4j; |
23 | import org.thingsboard.server.actors.ActorSystemContext; | 20 | import org.thingsboard.server.actors.ActorSystemContext; |
24 | import org.thingsboard.server.actors.stats.StatsPersistTick; | 21 | import org.thingsboard.server.actors.stats.StatsPersistTick; |
25 | import org.thingsboard.server.common.data.id.EntityId; | 22 | import org.thingsboard.server.common.data.id.EntityId; |
26 | import org.thingsboard.server.common.data.id.TenantId; | 23 | import org.thingsboard.server.common.data.id.TenantId; |
27 | import org.thingsboard.server.common.data.plugin.ComponentLifecycleState; | 24 | import org.thingsboard.server.common.data.plugin.ComponentLifecycleState; |
28 | -import org.thingsboard.server.common.msg.TbMsg; | ||
29 | -import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; | ||
30 | - | ||
31 | -import javax.annotation.Nullable; | ||
32 | -import java.util.function.Consumer; | 25 | +import org.thingsboard.server.common.msg.queue.PartitionChangeMsg; |
33 | 26 | ||
34 | @Slf4j | 27 | @Slf4j |
35 | public abstract class ComponentMsgProcessor<T extends EntityId> extends AbstractContextAwareMsgProcessor { | 28 | public abstract class ComponentMsgProcessor<T extends EntityId> extends AbstractContextAwareMsgProcessor { |
@@ -50,7 +43,7 @@ public abstract class ComponentMsgProcessor<T extends EntityId> extends Abstract | @@ -50,7 +43,7 @@ public abstract class ComponentMsgProcessor<T extends EntityId> extends Abstract | ||
50 | 43 | ||
51 | public abstract void stop(ActorContext context) throws Exception; | 44 | public abstract void stop(ActorContext context) throws Exception; |
52 | 45 | ||
53 | - public abstract void onClusterEventMsg(ClusterEventMsg msg) throws Exception; | 46 | + public abstract void onPartitionChangeMsg(PartitionChangeMsg msg) throws Exception; |
54 | 47 | ||
55 | public void onCreated(ActorContext context) throws Exception { | 48 | public void onCreated(ActorContext context) throws Exception { |
56 | start(context); | 49 | start(context); |
application/src/main/java/org/thingsboard/server/actors/shared/EntityActorsManager.java
deleted
100644 → 0
1 | -/** | ||
2 | - * Copyright © 2016-2020 The Thingsboard Authors | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.thingsboard.server.actors.shared; | ||
17 | - | ||
18 | -import akka.actor.ActorContext; | ||
19 | -import akka.actor.ActorRef; | ||
20 | -import akka.actor.Props; | ||
21 | -import akka.actor.UntypedActor; | ||
22 | -import akka.japi.Creator; | ||
23 | -import com.google.common.collect.BiMap; | ||
24 | -import com.google.common.collect.HashBiMap; | ||
25 | -import lombok.extern.slf4j.Slf4j; | ||
26 | -import org.thingsboard.server.actors.ActorSystemContext; | ||
27 | -import org.thingsboard.server.actors.service.ContextAwareActor; | ||
28 | -import org.thingsboard.server.common.data.SearchTextBased; | ||
29 | -import org.thingsboard.server.common.data.id.EntityId; | ||
30 | -import org.thingsboard.server.common.data.id.TenantId; | ||
31 | -import org.thingsboard.server.common.data.id.UUIDBased; | ||
32 | -import org.thingsboard.server.common.data.page.PageDataIterable; | ||
33 | - | ||
34 | -import java.util.HashMap; | ||
35 | -import java.util.Map; | ||
36 | - | ||
37 | -/** | ||
38 | - * Created by ashvayka on 15.03.18. | ||
39 | - */ | ||
40 | -@Slf4j | ||
41 | -public abstract class EntityActorsManager<T extends EntityId, A extends UntypedActor, M extends SearchTextBased<? extends UUIDBased>> { | ||
42 | - | ||
43 | - protected final ActorSystemContext systemContext; | ||
44 | - protected final BiMap<T, ActorRef> actors; | ||
45 | - | ||
46 | - public EntityActorsManager(ActorSystemContext systemContext) { | ||
47 | - this.systemContext = systemContext; | ||
48 | - this.actors = HashBiMap.create(); | ||
49 | - } | ||
50 | - | ||
51 | - protected abstract TenantId getTenantId(); | ||
52 | - | ||
53 | - protected abstract String getDispatcherName(); | ||
54 | - | ||
55 | - protected abstract Creator<A> creator(T entityId); | ||
56 | - | ||
57 | - protected abstract PageDataIterable.FetchFunction<M> getFetchEntitiesFunction(); | ||
58 | - | ||
59 | - public void init(ActorContext context) { | ||
60 | - for (M entity : new PageDataIterable<>(getFetchEntitiesFunction(), ContextAwareActor.ENTITY_PACK_LIMIT)) { | ||
61 | - T entityId = (T) entity.getId(); | ||
62 | - log.debug("[{}|{}] Creating entity actor", entityId.getEntityType(), entityId.getId()); | ||
63 | - //TODO: remove this cast making UUIDBased subclass of EntityId an interface and vice versa. | ||
64 | - ActorRef actorRef = getOrCreateActor(context, entityId); | ||
65 | - visit(entity, actorRef); | ||
66 | - log.debug("[{}|{}] Entity actor created.", entityId.getEntityType(), entityId.getId()); | ||
67 | - } | ||
68 | - } | ||
69 | - | ||
70 | - public void visit(M entity, ActorRef actorRef) { | ||
71 | - } | ||
72 | - | ||
73 | - public ActorRef getOrCreateActor(ActorContext context, T entityId) { | ||
74 | - return actors.computeIfAbsent(entityId, eId -> | ||
75 | - context.actorOf(Props.create(creator(eId)) | ||
76 | - .withDispatcher(getDispatcherName()), eId.toString())); | ||
77 | - } | ||
78 | - | ||
79 | - public void broadcast(Object msg) { | ||
80 | - actors.values().forEach(actorRef -> actorRef.tell(msg, ActorRef.noSender())); | ||
81 | - } | ||
82 | - | ||
83 | - public void remove(T id) { | ||
84 | - actors.remove(id); | ||
85 | - } | ||
86 | - | ||
87 | -} |
@@ -24,7 +24,6 @@ import org.thingsboard.server.actors.service.ContextBasedCreator; | @@ -24,7 +24,6 @@ import org.thingsboard.server.actors.service.ContextBasedCreator; | ||
24 | import org.thingsboard.server.common.data.DataConstants; | 24 | import org.thingsboard.server.common.data.DataConstants; |
25 | import org.thingsboard.server.common.data.Event; | 25 | import org.thingsboard.server.common.data.Event; |
26 | import org.thingsboard.server.common.msg.TbActorMsg; | 26 | import org.thingsboard.server.common.msg.TbActorMsg; |
27 | -import org.thingsboard.server.common.msg.cluster.ServerAddress; | ||
28 | 27 | ||
29 | @Slf4j | 28 | @Slf4j |
30 | public class StatsActor extends ContextAwareActor { | 29 | public class StatsActor extends ContextAwareActor { |
@@ -58,12 +57,12 @@ public class StatsActor extends ContextAwareActor { | @@ -58,12 +57,12 @@ public class StatsActor extends ContextAwareActor { | ||
58 | event.setEntityId(msg.getEntityId()); | 57 | event.setEntityId(msg.getEntityId()); |
59 | event.setTenantId(msg.getTenantId()); | 58 | event.setTenantId(msg.getTenantId()); |
60 | event.setType(DataConstants.STATS); | 59 | event.setType(DataConstants.STATS); |
61 | - event.setBody(toBodyJson(systemContext.getDiscoveryService().getCurrentServer().getServerAddress(), msg.getMessagesProcessed(), msg.getErrorsOccurred())); | 60 | + event.setBody(toBodyJson(systemContext.getServiceInfoProvider().getServiceId(), msg.getMessagesProcessed(), msg.getErrorsOccurred())); |
62 | systemContext.getEventService().save(event); | 61 | systemContext.getEventService().save(event); |
63 | } | 62 | } |
64 | 63 | ||
65 | - private JsonNode toBodyJson(ServerAddress server, long messagesProcessed, long errorsOccurred) { | ||
66 | - return mapper.createObjectNode().put("server", server.toString()).put("messagesProcessed", messagesProcessed).put("errorsOccurred", errorsOccurred); | 64 | + private JsonNode toBodyJson(String serviceId, long messagesProcessed, long errorsOccurred) { |
65 | + return mapper.createObjectNode().put("server", serviceId).put("messagesProcessed", messagesProcessed).put("errorsOccurred", errorsOccurred); | ||
67 | } | 66 | } |
68 | 67 | ||
69 | public static class ActorCreator extends ContextBasedCreator<StatsActor> { | 68 | public static class ActorCreator extends ContextBasedCreator<StatsActor> { |
@@ -22,41 +22,43 @@ import akka.actor.OneForOneStrategy; | @@ -22,41 +22,43 @@ import akka.actor.OneForOneStrategy; | ||
22 | import akka.actor.Props; | 22 | import akka.actor.Props; |
23 | import akka.actor.SupervisorStrategy; | 23 | import akka.actor.SupervisorStrategy; |
24 | import akka.actor.Terminated; | 24 | import akka.actor.Terminated; |
25 | -import akka.japi.Function; | ||
26 | import com.google.common.collect.BiMap; | 25 | import com.google.common.collect.BiMap; |
27 | import com.google.common.collect.HashBiMap; | 26 | import com.google.common.collect.HashBiMap; |
28 | -import lombok.extern.slf4j.Slf4j; | ||
29 | import org.thingsboard.server.actors.ActorSystemContext; | 27 | import org.thingsboard.server.actors.ActorSystemContext; |
30 | import org.thingsboard.server.actors.device.DeviceActorCreator; | 28 | import org.thingsboard.server.actors.device.DeviceActorCreator; |
31 | -import org.thingsboard.server.actors.device.DeviceActorToRuleEngineMsg; | ||
32 | import org.thingsboard.server.actors.ruleChain.RuleChainManagerActor; | 29 | import org.thingsboard.server.actors.ruleChain.RuleChainManagerActor; |
33 | import org.thingsboard.server.actors.service.ContextBasedCreator; | 30 | import org.thingsboard.server.actors.service.ContextBasedCreator; |
34 | import org.thingsboard.server.actors.service.DefaultActorService; | 31 | import org.thingsboard.server.actors.service.DefaultActorService; |
35 | -import org.thingsboard.server.actors.shared.rulechain.TenantRuleChainManager; | ||
36 | import org.thingsboard.server.common.data.EntityType; | 32 | import org.thingsboard.server.common.data.EntityType; |
33 | +import org.thingsboard.server.common.data.Tenant; | ||
37 | import org.thingsboard.server.common.data.id.DeviceId; | 34 | import org.thingsboard.server.common.data.id.DeviceId; |
38 | import org.thingsboard.server.common.data.id.RuleChainId; | 35 | import org.thingsboard.server.common.data.id.RuleChainId; |
39 | import org.thingsboard.server.common.data.id.TenantId; | 36 | import org.thingsboard.server.common.data.id.TenantId; |
40 | -import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; | ||
41 | import org.thingsboard.server.common.data.rule.RuleChain; | 37 | import org.thingsboard.server.common.data.rule.RuleChain; |
38 | +import org.thingsboard.server.common.msg.MsgType; | ||
42 | import org.thingsboard.server.common.msg.TbActorMsg; | 39 | import org.thingsboard.server.common.msg.TbActorMsg; |
40 | +import org.thingsboard.server.common.msg.TbMsg; | ||
43 | import org.thingsboard.server.common.msg.aware.DeviceAwareMsg; | 41 | import org.thingsboard.server.common.msg.aware.DeviceAwareMsg; |
44 | import org.thingsboard.server.common.msg.aware.RuleChainAwareMsg; | 42 | import org.thingsboard.server.common.msg.aware.RuleChainAwareMsg; |
45 | import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; | 43 | import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; |
46 | -import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg; | 44 | +import org.thingsboard.server.common.msg.queue.PartitionChangeMsg; |
45 | +import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg; | ||
46 | +import org.thingsboard.server.common.msg.queue.RuleEngineException; | ||
47 | +import org.thingsboard.server.common.msg.queue.ServiceType; | ||
47 | import scala.concurrent.duration.Duration; | 48 | import scala.concurrent.duration.Duration; |
48 | 49 | ||
49 | -import java.util.HashMap; | ||
50 | -import java.util.Map; | 50 | +import java.util.List; |
51 | +import java.util.Optional; | ||
52 | +import java.util.stream.Collectors; | ||
51 | 53 | ||
52 | public class TenantActor extends RuleChainManagerActor { | 54 | public class TenantActor extends RuleChainManagerActor { |
53 | 55 | ||
54 | - private final TenantId tenantId; | ||
55 | private final BiMap<DeviceId, ActorRef> deviceActors; | 56 | private final BiMap<DeviceId, ActorRef> deviceActors; |
57 | + private boolean isRuleEngineForCurrentTenant; | ||
58 | + private boolean isCore; | ||
56 | 59 | ||
57 | private TenantActor(ActorSystemContext systemContext, TenantId tenantId) { | 60 | private TenantActor(ActorSystemContext systemContext, TenantId tenantId) { |
58 | - super(systemContext, new TenantRuleChainManager(systemContext, tenantId)); | ||
59 | - this.tenantId = tenantId; | 61 | + super(systemContext, tenantId); |
60 | this.deviceActors = HashBiMap.create(); | 62 | this.deviceActors = HashBiMap.create(); |
61 | } | 63 | } |
62 | 64 | ||
@@ -65,12 +67,37 @@ public class TenantActor extends RuleChainManagerActor { | @@ -65,12 +67,37 @@ public class TenantActor extends RuleChainManagerActor { | ||
65 | return strategy; | 67 | return strategy; |
66 | } | 68 | } |
67 | 69 | ||
70 | + boolean cantFindTenant = false; | ||
71 | + | ||
68 | @Override | 72 | @Override |
69 | public void preStart() { | 73 | public void preStart() { |
70 | log.info("[{}] Starting tenant actor.", tenantId); | 74 | log.info("[{}] Starting tenant actor.", tenantId); |
71 | try { | 75 | try { |
72 | - initRuleChains(); | ||
73 | - log.info("[{}] Tenant actor started.", tenantId); | 76 | + Tenant tenant = systemContext.getTenantService().findTenantById(tenantId); |
77 | + if (tenant == null) { | ||
78 | + cantFindTenant = true; | ||
79 | + log.info("[{}] Started tenant actor for missing tenant.", tenantId); | ||
80 | + } else { | ||
81 | + // This Service may be started for specific tenant only. | ||
82 | + Optional<TenantId> isolatedTenantId = systemContext.getServiceInfoProvider().getIsolatedTenant(); | ||
83 | + | ||
84 | + isRuleEngineForCurrentTenant = systemContext.getServiceInfoProvider().isService(ServiceType.TB_RULE_ENGINE); | ||
85 | + isCore = systemContext.getServiceInfoProvider().isService(ServiceType.TB_CORE); | ||
86 | + | ||
87 | + if (isRuleEngineForCurrentTenant) { | ||
88 | + try { | ||
89 | + if (isolatedTenantId.map(id -> id.equals(tenantId)).orElseGet(() -> !tenant.isIsolatedTbRuleEngine())) { | ||
90 | + log.info("[{}] Going to init rule chains", tenantId); | ||
91 | + initRuleChains(); | ||
92 | + } else { | ||
93 | + isRuleEngineForCurrentTenant = false; | ||
94 | + } | ||
95 | + } catch (Exception e) { | ||
96 | + cantFindTenant = true; | ||
97 | + } | ||
98 | + } | ||
99 | + log.info("[{}] Tenant actor started.", tenantId); | ||
100 | + } | ||
74 | } catch (Exception e) { | 101 | } catch (Exception e) { |
75 | log.warn("[{}] Unknown failure", tenantId, e); | 102 | log.warn("[{}] Unknown failure", tenantId, e); |
76 | } | 103 | } |
@@ -83,18 +110,36 @@ public class TenantActor extends RuleChainManagerActor { | @@ -83,18 +110,36 @@ public class TenantActor extends RuleChainManagerActor { | ||
83 | 110 | ||
84 | @Override | 111 | @Override |
85 | protected boolean process(TbActorMsg msg) { | 112 | protected boolean process(TbActorMsg msg) { |
113 | + if (cantFindTenant) { | ||
114 | + log.info("[{}] Processing missing Tenant msg: {}", tenantId, msg); | ||
115 | + if (msg.getMsgType().equals(MsgType.QUEUE_TO_RULE_ENGINE_MSG)) { | ||
116 | + QueueToRuleEngineMsg queueMsg = (QueueToRuleEngineMsg) msg; | ||
117 | + queueMsg.getTbMsg().getCallback().onSuccess(); | ||
118 | + } | ||
119 | + return true; | ||
120 | + } | ||
86 | switch (msg.getMsgType()) { | 121 | switch (msg.getMsgType()) { |
87 | - case CLUSTER_EVENT_MSG: | ||
88 | - broadcast(msg); | 122 | + case PARTITION_CHANGE_MSG: |
123 | + PartitionChangeMsg partitionChangeMsg = (PartitionChangeMsg) msg; | ||
124 | + ServiceType serviceType = partitionChangeMsg.getServiceQueueKey().getServiceType(); | ||
125 | + if (ServiceType.TB_RULE_ENGINE.equals(serviceType)) { | ||
126 | + //To Rule Chain Actors | ||
127 | + broadcast(msg); | ||
128 | + } else if (ServiceType.TB_CORE.equals(serviceType)) { | ||
129 | + //To Device Actors | ||
130 | + List<DeviceId> repartitionedDevices = | ||
131 | + deviceActors.keySet().stream().filter(deviceId -> !isMyPartition(deviceId)).collect(Collectors.toList()); | ||
132 | + for (DeviceId deviceId : repartitionedDevices) { | ||
133 | + ActorRef deviceActor = deviceActors.remove(deviceId); | ||
134 | + context().stop(deviceActor); | ||
135 | + } | ||
136 | + } | ||
89 | break; | 137 | break; |
90 | case COMPONENT_LIFE_CYCLE_MSG: | 138 | case COMPONENT_LIFE_CYCLE_MSG: |
91 | onComponentLifecycleMsg((ComponentLifecycleMsg) msg); | 139 | onComponentLifecycleMsg((ComponentLifecycleMsg) msg); |
92 | break; | 140 | break; |
93 | - case SERVICE_TO_RULE_ENGINE_MSG: | ||
94 | - onServiceToRuleEngineMsg((ServiceToRuleEngineMsg) msg); | ||
95 | - break; | ||
96 | - case DEVICE_ACTOR_TO_RULE_ENGINE_MSG: | ||
97 | - onDeviceActorToRuleEngineMsg((DeviceActorToRuleEngineMsg) msg); | 141 | + case QUEUE_TO_RULE_ENGINE_MSG: |
142 | + onQueueToRuleEngineMsg((QueueToRuleEngineMsg) msg); | ||
98 | break; | 143 | break; |
99 | case TRANSPORT_TO_DEVICE_ACTOR_MSG: | 144 | case TRANSPORT_TO_DEVICE_ACTOR_MSG: |
100 | case DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG: | 145 | case DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG: |
@@ -105,7 +150,6 @@ public class TenantActor extends RuleChainManagerActor { | @@ -105,7 +150,6 @@ public class TenantActor extends RuleChainManagerActor { | ||
105 | onToDeviceActorMsg((DeviceAwareMsg) msg); | 150 | onToDeviceActorMsg((DeviceAwareMsg) msg); |
106 | break; | 151 | break; |
107 | case RULE_CHAIN_TO_RULE_CHAIN_MSG: | 152 | case RULE_CHAIN_TO_RULE_CHAIN_MSG: |
108 | - case REMOTE_TO_RULE_CHAIN_TELL_NEXT_MSG: | ||
109 | onRuleChainMsg((RuleChainAwareMsg) msg); | 153 | onRuleChainMsg((RuleChainAwareMsg) msg); |
110 | break; | 154 | break; |
111 | default: | 155 | default: |
@@ -114,41 +158,59 @@ public class TenantActor extends RuleChainManagerActor { | @@ -114,41 +158,59 @@ public class TenantActor extends RuleChainManagerActor { | ||
114 | return true; | 158 | return true; |
115 | } | 159 | } |
116 | 160 | ||
117 | - private void onServiceToRuleEngineMsg(ServiceToRuleEngineMsg msg) { | ||
118 | - if (ruleChainManager.getRootChainActor() != null) { | ||
119 | - ruleChainManager.getRootChainActor().tell(msg, self()); | ||
120 | - } else { | ||
121 | - log.info("[{}] No Root Chain: {}", tenantId, msg); | ||
122 | - } | 161 | + private boolean isMyPartition(DeviceId deviceId) { |
162 | + return systemContext.resolve(ServiceType.TB_CORE, tenantId, deviceId).isMyPartition(); | ||
123 | } | 163 | } |
124 | 164 | ||
125 | - private void onDeviceActorToRuleEngineMsg(DeviceActorToRuleEngineMsg msg) { | ||
126 | - if (ruleChainManager.getRootChainActor() != null) { | ||
127 | - ruleChainManager.getRootChainActor().tell(msg, self()); | 165 | + private void onQueueToRuleEngineMsg(QueueToRuleEngineMsg msg) { |
166 | + if (!isRuleEngineForCurrentTenant) { | ||
167 | + log.warn("RECEIVED INVALID MESSAGE: {}", msg); | ||
168 | + return; | ||
169 | + } | ||
170 | + TbMsg tbMsg = msg.getTbMsg(); | ||
171 | + if (tbMsg.getRuleChainId() == null) { | ||
172 | + if (getRootChainActor() != null) { | ||
173 | + getRootChainActor().tell(msg, self()); | ||
174 | + } else { | ||
175 | + tbMsg.getCallback().onFailure(new RuleEngineException("No Root Rule Chain available!")); | ||
176 | + log.info("[{}] No Root Chain: {}", tenantId, msg); | ||
177 | + } | ||
128 | } else { | 178 | } else { |
129 | - log.info("[{}] No Root Chain: {}", tenantId, msg); | 179 | + ActorRef ruleChainActor = get(tbMsg.getRuleChainId()); |
180 | + if (ruleChainActor != null) { | ||
181 | + ruleChainActor.tell(msg, self()); | ||
182 | + } else { | ||
183 | + log.trace("Received message for non-existing rule chain: [{}]", tbMsg.getRuleChainId()); | ||
184 | + //TODO: 3.1 Log it to dead letters queue; | ||
185 | + tbMsg.getCallback().onSuccess(); | ||
186 | + } | ||
130 | } | 187 | } |
131 | } | 188 | } |
132 | 189 | ||
133 | private void onRuleChainMsg(RuleChainAwareMsg msg) { | 190 | private void onRuleChainMsg(RuleChainAwareMsg msg) { |
134 | - ruleChainManager.getOrCreateActor(context(), msg.getRuleChainId()).tell(msg, self()); | 191 | + getOrCreateActor(context(), msg.getRuleChainId()).tell(msg, self()); |
135 | } | 192 | } |
136 | 193 | ||
137 | private void onToDeviceActorMsg(DeviceAwareMsg msg) { | 194 | private void onToDeviceActorMsg(DeviceAwareMsg msg) { |
195 | + if (!isCore) { | ||
196 | + log.warn("RECEIVED INVALID MESSAGE: {}", msg); | ||
197 | + } | ||
138 | getOrCreateDeviceActor(msg.getDeviceId()).tell(msg, ActorRef.noSender()); | 198 | getOrCreateDeviceActor(msg.getDeviceId()).tell(msg, ActorRef.noSender()); |
139 | } | 199 | } |
140 | 200 | ||
141 | private void onComponentLifecycleMsg(ComponentLifecycleMsg msg) { | 201 | private void onComponentLifecycleMsg(ComponentLifecycleMsg msg) { |
142 | - ActorRef target = getEntityActorRef(msg.getEntityId()); | ||
143 | - if (target != null) { | ||
144 | - if (msg.getEntityId().getEntityType() == EntityType.RULE_CHAIN) { | ||
145 | - RuleChain ruleChain = systemContext.getRuleChainService(). | ||
146 | - findRuleChainById(tenantId, new RuleChainId(msg.getEntityId().getId())); | ||
147 | - ruleChainManager.visit(ruleChain, target); | 202 | + if (isRuleEngineForCurrentTenant) { |
203 | + ActorRef target = getEntityActorRef(msg.getEntityId()); | ||
204 | + if (target != null) { | ||
205 | + if (msg.getEntityId().getEntityType() == EntityType.RULE_CHAIN) { | ||
206 | + RuleChain ruleChain = systemContext.getRuleChainService(). | ||
207 | + findRuleChainById(tenantId, new RuleChainId(msg.getEntityId().getId())); | ||
208 | + visit(ruleChain, target); | ||
209 | + } | ||
210 | + target.tell(msg, ActorRef.noSender()); | ||
211 | + } else { | ||
212 | + log.debug("[{}] Invalid component lifecycle msg: {}", tenantId, msg); | ||
148 | } | 213 | } |
149 | - target.tell(msg, ActorRef.noSender()); | ||
150 | - } else { | ||
151 | - log.debug("[{}] Invalid component lifecycle msg: {}", tenantId, msg); | ||
152 | } | 214 | } |
153 | } | 215 | } |
154 | 216 | ||
@@ -172,7 +234,7 @@ public class TenantActor extends RuleChainManagerActor { | @@ -172,7 +234,7 @@ public class TenantActor extends RuleChainManagerActor { | ||
172 | if (removed) { | 234 | if (removed) { |
173 | log.debug("[{}] Removed actor:", terminated); | 235 | log.debug("[{}] Removed actor:", terminated); |
174 | } else { | 236 | } else { |
175 | - log.warn("[{}] Removed actor was not found in the device map!"); | 237 | + log.debug("Removed actor was not found in the device map!"); |
176 | } | 238 | } |
177 | } else { | 239 | } else { |
178 | throw new IllegalStateException("Remote actors are not supported!"); | 240 | throw new IllegalStateException("Remote actors are not supported!"); |
@@ -195,15 +257,12 @@ public class TenantActor extends RuleChainManagerActor { | @@ -195,15 +257,12 @@ public class TenantActor extends RuleChainManagerActor { | ||
195 | } | 257 | } |
196 | } | 258 | } |
197 | 259 | ||
198 | - private final SupervisorStrategy strategy = new OneForOneStrategy(3, Duration.create("1 minute"), new Function<Throwable, SupervisorStrategy.Directive>() { | ||
199 | - @Override | ||
200 | - public SupervisorStrategy.Directive apply(Throwable t) { | ||
201 | - log.warn("[{}] Unknown failure", tenantId, t); | ||
202 | - if (t instanceof ActorInitializationException) { | ||
203 | - return SupervisorStrategy.stop(); | ||
204 | - } else { | ||
205 | - return SupervisorStrategy.resume(); | ||
206 | - } | 260 | + private final SupervisorStrategy strategy = new OneForOneStrategy(3, Duration.create("1 minute"), t -> { |
261 | + log.warn("[{}] Unknown failure", tenantId, t); | ||
262 | + if (t instanceof ActorInitializationException) { | ||
263 | + return SupervisorStrategy.stop(); | ||
264 | + } else { | ||
265 | + return SupervisorStrategy.resume(); | ||
207 | } | 266 | } |
208 | }); | 267 | }); |
209 | 268 |