diff --git a/src/ServicePulse.Host/app/css/particular.css b/src/ServicePulse.Host/app/css/particular.css index 56a96c6e81..e34b5a0144 100644 --- a/src/ServicePulse.Host/app/css/particular.css +++ b/src/ServicePulse.Host/app/css/particular.css @@ -3370,4 +3370,159 @@ section[name="platformconnection"] ol { section[name="platformconnection"] li { margin-bottom: 15px; +} + +.link { + fill: none; + stroke: #ccc; + stroke-width: 2px; +} +.link.event{ + stroke-dasharray: 5,3; +} + +.pa-flow-saga { + background-image: url('../img/saga.svg'); + background-position: center; + background-repeat: no-repeat; + height: 15px; + width: 15px; + margin-left: 20px; +} + +.pa-flow-timeout { + background-image: url('../img/timeout.svg'); + background-position: center; + background-repeat: no-repeat; + height: 15px; + width: 15px; +} + +.pa-flow-event { + background-image: url('../img/event.svg'); + background-position: center; + background-repeat: no-repeat; + height: 15px; + width: 15px; +} + +.pa-flow-command { + background-image: url('../img/command.svg'); + background-position: center; + background-repeat: no-repeat; + height: 15px; + width: 15px; +} + +.pa-flow-failed { + background-image: url('../img/failed-msg.svg'); + background-position: center; + background-repeat: no-repeat; + height: 15px; + width: 15px; +} + +.node rect { + fill: #fff; + stroke: #cccbcc; + stroke-width: 3px; +} + +.node rect.error { + stroke: red; +} + +.node text { + font: 12px sans-serif; +} + +.node .time-sent sp-moment { + display: block; + margin-left: 20px; + padding-top: 0; + color: #777f7f; + text-transform: capitalize; +} + +.node-text { + padding: 3px 8px 1px; +} + +.node-text i { + display: inline-block; + position: relative; + top: -1px; + margin-right: 5px; + filter: brightness(0) saturate(100%) invert(0%) sepia(0%) saturate(0%) hue-rotate(346deg) brightness(104%) contrast(104%); +} + +.node-text .lead { + display: inline-block; + width: 204px; + position: relative; + top: 4px; +} + +g.error .node-text .lead, g.current-message.error .node-text .lead { + width: 184px; +} + +.node-text .lead.saga { + font-weight: normal; + width: 182px; +} + +g.current-message.error rect { + stroke: #be514a; + fill: #be514a !important; +} + +g.current-message.error .node-text, g.current-message .node-text .lead { + color: #fff !important; +} + +g.error .node-text i:not(.pa-flow-saga) { + filter: brightness(0) saturate(100%) invert(46%) sepia(9%) saturate(4493%) hue-rotate(317deg) brightness(81%) contrast(82%); +} + +g.current-message.error .node-text i { + color: #fff; + filter: brightness(0) saturate(100%) invert(100%) sepia(0%) saturate(7475%) hue-rotate(21deg) brightness(100%) contrast(106%); +} + +g.current-message.error .node-text strong { + color: #fff; +} + +g.current-message.error .node-text .time-sent sp-moment { + color: #ffcecb !important; +} + +g.error rect { + stroke: #be514a; +} + +g.current-message.error .node-text a { + color: #fff; +} + +g.current-message.error .node-text a:hover { + cursor: text; + text-decoration: none; +} + +g.error .node-text a { + color: #be514a; +} + +g.error .node-text .time-sent sp-moment { + color: #be514a; +} + +g.error .node-text .lead.saga { + color: #be514a; +} + +g.error .node-text a:hover { + text-decoration: underline; } \ No newline at end of file diff --git a/src/ServicePulse.Host/app/img/command.svg b/src/ServicePulse.Host/app/img/command.svg new file mode 100644 index 0000000000..9f39793085 --- /dev/null +++ b/src/ServicePulse.Host/app/img/command.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/ServicePulse.Host/app/img/event.svg b/src/ServicePulse.Host/app/img/event.svg new file mode 100644 index 0000000000..c4222f78c9 --- /dev/null +++ b/src/ServicePulse.Host/app/img/event.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/ServicePulse.Host/app/img/failed-msg.svg b/src/ServicePulse.Host/app/img/failed-msg.svg new file mode 100644 index 0000000000..2f581c9d49 --- /dev/null +++ b/src/ServicePulse.Host/app/img/failed-msg.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/ServicePulse.Host/app/img/saga.svg b/src/ServicePulse.Host/app/img/saga.svg new file mode 100644 index 0000000000..f284fcc527 --- /dev/null +++ b/src/ServicePulse.Host/app/img/saga.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/ServicePulse.Host/app/img/timeout.svg b/src/ServicePulse.Host/app/img/timeout.svg new file mode 100644 index 0000000000..40869a1988 --- /dev/null +++ b/src/ServicePulse.Host/app/img/timeout.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/ServicePulse.Host/app/index.html b/src/ServicePulse.Host/app/index.html index ce01d6c5bb..eea7b9d433 100644 --- a/src/ServicePulse.Host/app/index.html +++ b/src/ServicePulse.Host/app/index.html @@ -191,6 +191,7 @@

Warning!

+ diff --git a/src/ServicePulse.Host/app/js/directives/ui.particular.flow-diagram.js b/src/ServicePulse.Host/app/js/directives/ui.particular.flow-diagram.js new file mode 100644 index 0000000000..cc82276178 --- /dev/null +++ b/src/ServicePulse.Host/app/js/directives/ui.particular.flow-diagram.js @@ -0,0 +1,298 @@ +(function (window, angular, d3) { + 'use strict'; + + + function controller($scope, serviceControlService, $routeParams, $compile) { + + function createTreeStructure(messages) { + var map = {}, node, roots = [], i; + + for (i = 0; i < messages.length; i += 1) { + map[messages[i].messageId] = i; // initialize the map + messages[i].children = []; // initialize the children + } + + for (i = 0; i < messages.length; i += 1) { + node = messages[i]; + if (node.parentId && map[node.parentId] ) { + // if you have dangling branches check that map[node.parentId] exists + messages[map[node.parentId]].children.push(node); + } else { + roots.push(node); + } + } + return roots; + } + + function mapMessage(message) { + var parentid, saga = ''; + var header = message.headers.find(function(x) { return x.key === 'NServiceBus.RelatedTo';}); + if(header){ + parentid = header.value; + } + var sagaHeader = message.headers.find(function(x) { return x.key === 'NServiceBus.OriginatingSagaType';}); + if(sagaHeader){ + saga = sagaHeader.value.split(', ')[0]; + } + + return { + "nodeName": message.message_type, + "id": message.id, + "messageId": message.message_id, + "parentId": parentid, + "type": message.headers.findIndex(function(x) { return x.key === 'NServiceBus.DeliverAt'; }) > -1 ? 'Timeout message' : message.headers.find(function(x) { return x.key === 'NServiceBus.MessageIntent'; }).value === 'Publish' ? 'Event message' : 'Command message', + "isError": message.headers.findIndex(function(x) { return x.key === 'NServiceBus.ExceptionInfo.ExceptionType'; }) > -1, + "sagaName": saga, + "link" : { + "name" : "Link "+message.id, + "nodeName" : message.id + }, + "timeSent": new Date(message.time_sent) + }; + } + + // Set the dimensions and margins of the diagram + var margin = {top: 20, right: 90, bottom: 30, left: 90}, + width = 3600 - margin.left - margin.right; + + var rectNode = { width : 250, height : 90, textMargin : 5 } + + + var i = 0, + duration = 750, + root, treemap, svg, parentSvg; + + var currentMessageId = $routeParams.messageId; + + function drawTree(treeData) { + // Assigns parent, children, height, depth + root = d3.hierarchy(treeData, function (d) { + return d.children; + }); + + // append the svg object to the body of the page +// appends a 'group' element to 'svg' +// moves the 'group' element to the top left margin + parentSvg = d3.select("#tree-container").append("svg") + .attr('viewBox', '-1000 -10 2000 2000'); + + svg = parentSvg.append("g") + .attr("transform", "scale(.7,.7)"); + + var zoom = d3.zoom() + .scaleExtent([1 / 2, 8]) + .on("zoom", zoomed); + + svg.append('defs').append('marker') + .attr('id', 'end-arrow') + .attr('viewBox', '0 -5 10 10') + .attr('refX', 0) + .attr('refY', 0) + .attr('markerWidth', 6) + .attr('markerHeight', 6) + .attr('orient', 'auto') + .attr('class', 'arrow') + .append('path') + .attr('d', 'M10,-5L0,0L10,5'); + + // declares a tree layout and assigns the size + treemap = d3.tree().nodeSize([rectNode.width + 20, rectNode.height]); + + root.x0 = width / 2; + root.y0 = 0; + + parentSvg.call(zoom); + + update(root); + } + + function zoomed() { + svg.attr("transform", d3.event.transform); + } + + function update(source) { + + // Assigns the x and y position for the nodes + var treeData = treemap(root); + + // Compute the new tree layout. + var nodes = treeData.descendants(), + links = treeData.descendants().slice(1); + + // Normalize for fixed-depth. + nodes.forEach(function(d){ d.y = d.depth * 180 }); + + // ****************** Nodes section *************************** + + // Update the nodes... + var node = svg.selectAll('g.node') + .data(nodes, function(d) {return d.id || (d.id = ++i); }); + + // Enter any new modes at the parent's previous position. + var nodeEnter = node.enter().append('g') + .attr('class', function(d){ return 'node ' + d.data.type.toLowerCase() + ' ' + (d.data.isError ? 'error' : '') + ' ' + (d.data.id === currentMessageId ? 'current-message' : '');}) + .attr('transform', function(d) { + return 'translate(' + source.x0 + "," + source.y0 + ')'; + }) + .on('click', click); + + // Add rectangle for the nodes + nodeEnter.append('rect') + .attr('rx', 6) + .attr('ry', 6) + .attr('width', rectNode.width) + .attr('height', function(d) { + return !d.data.sagaName ? rectNode.height - 22 : rectNode.height; + }) + .style("fill", function(d) { + return d._children ? 'lightsteelblue' : '#fff'; + }); + + nodeEnter.append('foreignObject') + .attr('x', rectNode.textMargin) + .attr('y', rectNode.textMargin) + .attr('width', function() { + return (rectNode.width - rectNode.textMargin * 2) < 0 ? 0 + : (rectNode.width - rectNode.textMargin * 2) + }) + .attr('height', function(d) { + var height = rectNode.height; + if(!d.data.sagaName){ + height -= 10; + } + return (height - rectNode.textMargin * 2) < 0 ? 0 + : (height - rectNode.textMargin * 2) + }) + .append('xhtml').html(function(d) { + return '
' + + (d.data.isError ? '' : '') + + '
' + (d.data.isError ? '' + d.data.nodeName + '' : d.data.nodeName) + '
' + + '' + + (d.data.sagaName ? '
' + d.data.sagaName + '
' : '') + + '
'; + }).each(function(){ + $compile(this)($scope); + }); + + // UPDATE + var nodeUpdate = nodeEnter.merge(node); + + // Transition to the proper position for the node + nodeUpdate.transition() + .duration(duration) + .attr("transform", function(d) { + return "translate(" + d.x + "," + d.y + ")"; + }); + + // Update the node attributes and style + nodeUpdate.select('rect.node') + .attr('r', 10) + .style("fill", function(d) { + return d._children ? "lightsteelblue" : "#fff"; + }) + .attr('cursor', 'pointer'); + + + // Remove any exiting nodes + var nodeExit = node.exit().transition() + .duration(duration) + .attr("transform", function(d) { + return "translate(" + source.x + "," + source.y + ")"; + }) + .remove(); + + // On exit reduce the opacity of text labels + nodeExit.select('text') + .style('fill-opacity', 1e-6); + + // ****************** links section *************************** + + // Update the links... + var link = svg.selectAll('path.link') + .data(links, function(d) { return d.id; }); + + // Enter any new links at the parent's previous position. + var linkEnter = link.enter().insert('path', "g") + .attr("class", function(d){ + if(d.data.type === 'Event') + return 'link event'; + else + return 'link command'; + }) + .attr('marker-start', 'url(#end-arrow)') + .attr('d', function(d){ + var o = {x: source.x0, y: source.y0} + return straight(o, o); + }); + + // UPDATE + var linkUpdate = linkEnter.merge(link); + + // Transition back to the parent element position + linkUpdate.transition() + .duration(duration) + .attr('d', function(d){ return straight(d, d.parent) }); + + // Remove any exiting links + link.exit().transition() + .duration(duration) + .attr('d', function(d) { + var o = {x: source.x, y: source.y}; + return straight(o, o); + }) + .remove(); + + // Store the old positions for transition. + nodes.forEach(function(d){ + d.x0 = d.x; + d.y0 = d.y; + }); + + function straight(s, d){ + return 'M ' + (s.x + rectNode.width / 2) + ' ' + s.y + + ' C ' + (s.x + rectNode.width / 2) + ' ' + s.y + ' ,' + + (d.x + rectNode.width / 2) + ' ' + (d.y + rectNode.height - 22) + ' ,' + + (d.x + rectNode.width / 2) + ' ' + (d.y + rectNode.height - 22); + } + + // Toggle children on click. + function click(d) { + if (d.children) { + d._children = d.children; + d.children = null; + } else { + d.children = d._children; + d._children = null; + } + update(d); + } + } + + serviceControlService.getConversation($scope.conversationId).then(function(messages) { + var tree = createTreeStructure(messages.map(mapMessage)); + drawTree(tree[0]); + }); + } + + controller.$inject = ['$scope', 'serviceControlService', '$routeParams', '$compile']; + + function directive() { + return { + scope: { conversationId: '@' }, + restrict: 'E', + template: '
', + controller: controller + + }; + } + + directive.$inject = []; + + angular + .module('sc') + .directive('flowDiagram', directive); + +}(window, window.angular, window.d3)); + diff --git a/src/ServicePulse.Host/app/js/services/services.service-control.js b/src/ServicePulse.Host/app/js/services/services.service-control.js index 31e3268896..18ca636bb2 100644 --- a/src/ServicePulse.Host/app/js/services/services.service-control.js +++ b/src/ServicePulse.Host/app/js/services/services.service-control.js @@ -331,6 +331,14 @@ return $http.get(url); } + + function getConversation(conversationId) { + var url = uri.join(scu, 'conversations', conversationId); + return $http.get(url).then(function (response) { + return response.data; + }); + } + var service = { getServiceControlMetadata: getServiceControlMetadata, @@ -368,7 +376,8 @@ acknowledgeGroup: acknowledgeGroup, getFailedMessageById: getFailedMessageById, getEditAndRetryConfig: getEditAndRetryConfig, - retryEditedMessage : retryEditedMessage + retryEditedMessage : retryEditedMessage, + getConversation: getConversation }; return service; diff --git a/src/ServicePulse.Host/app/js/views/message/controller.js b/src/ServicePulse.Host/app/js/views/message/controller.js index 02c2886f12..473e57f399 100644 --- a/src/ServicePulse.Host/app/js/views/message/controller.js +++ b/src/ServicePulse.Host/app/js/views/message/controller.js @@ -66,6 +66,7 @@ if (!angular.isDefined(message.headers)) { return serviceControlService.getMessage(message.message_id).then(function (response) { message.headers = response.message.headers; + message.conversationId = message.headers.find(function(x){return x.key === 'NServiceBus.ConversationId';}).value; }, function () { message.headersUnavailable = "message headers unavailable"; }); diff --git a/src/ServicePulse.Host/app/js/views/message/messages-view.html b/src/ServicePulse.Host/app/js/views/message/messages-view.html index 99a6649a68..54eae4f0c2 100644 --- a/src/ServicePulse.Host/app/js/views/message/messages-view.html +++ b/src/ServicePulse.Host/app/js/views/message/messages-view.html @@ -65,6 +65,7 @@
Stacktrace
Headers
Message body
+
Flow Diagram
{{ vm.message.exception.message }}
@@ -82,6 +83,7 @@
{{vm.message.headersUnavailable}}
{{vm.message.messageBody}}
{{vm.message.bodyUnavailable}}
+ diff --git a/src/ServicePulse.Host/package-lock.json b/src/ServicePulse.Host/package-lock.json index 3ef65fd165..c280c09230 100644 --- a/src/ServicePulse.Host/package-lock.json +++ b/src/ServicePulse.Host/package-lock.json @@ -19,7 +19,7 @@ "angularjs-toaster": "^1.1.0", "animate.css": "^3.4.0", "bootstrap": "3.4.1", - "d3": "^4.9.1", + "d3": "^5.16.0", "highlight.js": "^11.3.1", "highlightjs-badge": "^0.1.9", "jquery": "^3.0.0", @@ -2235,40 +2235,41 @@ "dev": true }, "node_modules/d3": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/d3/-/d3-4.13.0.tgz", - "integrity": "sha512-l8c4+0SldjVKLaE2WG++EQlqD7mh/dmQjvi2L2lKPadAVC+TbJC4ci7Uk9bRi+To0+ansgsS0iWfPjD7DBy+FQ==", - "dependencies": { - "d3-array": "1.2.1", - "d3-axis": "1.0.8", - "d3-brush": "1.0.4", - "d3-chord": "1.0.4", - "d3-collection": "1.0.4", - "d3-color": "1.0.3", - "d3-dispatch": "1.0.3", - "d3-drag": "1.2.1", - "d3-dsv": "1.0.8", - "d3-ease": "1.0.3", - "d3-force": "1.1.0", - "d3-format": "1.2.2", - "d3-geo": "1.9.1", - "d3-hierarchy": "1.1.5", - "d3-interpolate": "1.1.6", - "d3-path": "1.0.5", - "d3-polygon": "1.0.3", - "d3-quadtree": "1.0.3", - "d3-queue": "3.0.7", - "d3-random": "1.1.0", - "d3-request": "1.0.6", - "d3-scale": "1.0.7", - "d3-selection": "1.3.0", - "d3-shape": "1.2.0", - "d3-time": "1.0.8", - "d3-time-format": "2.1.1", - "d3-timer": "1.0.7", - "d3-transition": "1.1.1", - "d3-voronoi": "1.1.2", - "d3-zoom": "1.7.1" + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/d3/-/d3-5.16.0.tgz", + "integrity": "sha512-4PL5hHaHwX4m7Zr1UapXW23apo6pexCgdetdJ5kTmADpG/7T9Gkxw0M0tf/pjoB63ezCCm0u5UaFYy2aMt0Mcw==", + "dependencies": { + "d3-array": "1", + "d3-axis": "1", + "d3-brush": "1", + "d3-chord": "1", + "d3-collection": "1", + "d3-color": "1", + "d3-contour": "1", + "d3-dispatch": "1", + "d3-drag": "1", + "d3-dsv": "1", + "d3-ease": "1", + "d3-fetch": "1", + "d3-force": "1", + "d3-format": "1", + "d3-geo": "1", + "d3-hierarchy": "1", + "d3-interpolate": "1", + "d3-path": "1", + "d3-polygon": "1", + "d3-quadtree": "1", + "d3-random": "1", + "d3-scale": "2", + "d3-scale-chromatic": "1", + "d3-selection": "1", + "d3-shape": "1", + "d3-time": "1", + "d3-time-format": "2", + "d3-timer": "1", + "d3-transition": "1", + "d3-voronoi": "1", + "d3-zoom": "1" } }, "node_modules/d3-array": { @@ -2312,6 +2313,14 @@ "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.0.3.tgz", "integrity": "sha1-vHZD/KjlOoNH4vva/6I2eWtYUJs=" }, + "node_modules/d3-contour": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-1.3.2.tgz", + "integrity": "sha512-hoPp4K/rJCu0ladiH6zmJUEz6+u3lgR+GSm/QdM2BBvDraU39Vr7YdDCicJcxP1z8i9B/2dJLgDC1NcvlF8WCg==", + "dependencies": { + "d3-array": "^1.1.1" + } + }, "node_modules/d3-dispatch": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.3.tgz", @@ -2327,9 +2336,9 @@ } }, "node_modules/d3-dsv": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-1.0.8.tgz", - "integrity": "sha512-IVCJpQ+YGe3qu6odkPQI0KPqfxkhbP/oM1XhhE/DFiYmcXKfCRub4KXyiuehV1d4drjWVXHUWx4gHqhdZb6n/A==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-1.2.0.tgz", + "integrity": "sha512-9yVlqvZcSOMhCYzniHE7EVUws7Fa1zgw+/EAV2BxJoG3ME19V6BQFBwI855XQDsxyOuG7NibqRMTtiF/Qup46g==", "dependencies": { "commander": "2", "iconv-lite": "0.4", @@ -2352,6 +2361,14 @@ "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.3.tgz", "integrity": "sha1-aL+8NJM4o4DETYrMT7wzBKotjA4=" }, + "node_modules/d3-fetch": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-1.2.0.tgz", + "integrity": "sha512-yC78NBVcd2zFAyR/HnUiBS7Lf6inSCoWcSxFfw8FYL7ydiqe80SazNwoffcqOfs95XaLo7yebsmQqDKSsXUtvA==", + "dependencies": { + "d3-dsv": "1" + } + }, "node_modules/d3-force": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-1.1.0.tgz", @@ -2364,9 +2381,9 @@ } }, "node_modules/d3-format": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.2.2.tgz", - "integrity": "sha512-zH9CfF/3C8zUI47nsiKfD0+AGDEuM8LwBIP7pBVpyR4l/sKkZqITmMtxRp04rwBrlshIZ17XeFAaovN3++wzkw==" + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.4.5.tgz", + "integrity": "sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ==" }, "node_modules/d3-geo": { "version": "1.9.1", @@ -2404,41 +2421,33 @@ "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-1.0.3.tgz", "integrity": "sha1-rHmH4+I/6AWpkPKOG1DTj8uCJDg=" }, - "node_modules/d3-queue": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/d3-queue/-/d3-queue-3.0.7.tgz", - "integrity": "sha1-yTouVLQXwJWRKdfXP2z31Ckudhg=" - }, "node_modules/d3-random": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-1.1.0.tgz", "integrity": "sha1-ZkLlBsb6OmSFldKyRpeIqNElKdM=" }, - "node_modules/d3-request": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/d3-request/-/d3-request-1.0.6.tgz", - "integrity": "sha512-FJj8ySY6GYuAJHZMaCQ83xEYE4KbkPkmxZ3Hu6zA1xxG2GD+z6P+Lyp+zjdsHf0xEbp2xcluDI50rCS855EQ6w==", - "dependencies": { - "d3-collection": "1", - "d3-dispatch": "1", - "d3-dsv": "1", - "xmlhttprequest": "1" - } - }, "node_modules/d3-scale": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-1.0.7.tgz", - "integrity": "sha512-KvU92czp2/qse5tUfGms6Kjig0AhHOwkzXG0+PqIJB3ke0WUv088AHMZI0OssO9NCkXt4RP8yju9rpH8aGB7Lw==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-2.2.2.tgz", + "integrity": "sha512-LbeEvGgIb8UMcAa0EATLNX0lelKWGYDQiPdHj+gLblGVhGLyNbaCn3EvrJf0A3Y/uOOU5aD6MTh5ZFCdEwGiCw==", "dependencies": { "d3-array": "^1.2.0", "d3-collection": "1", - "d3-color": "1", "d3-format": "1", "d3-interpolate": "1", "d3-time": "1", "d3-time-format": "2" } }, + "node_modules/d3-scale-chromatic": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-1.5.0.tgz", + "integrity": "sha512-ACcL46DYImpRFMBcpk9HhtIyC7bTBR4fNOPxwVSl0LfulDAwyiHyPOTqcDG1+t5d4P9W7t/2NAuWu59aKko/cg==", + "dependencies": { + "d3-color": "1", + "d3-interpolate": "1" + } + }, "node_modules/d3-selection": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.3.0.tgz", @@ -2453,14 +2462,14 @@ } }, "node_modules/d3-time": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.0.8.tgz", - "integrity": "sha512-YRZkNhphZh3KcnBfitvF3c6E0JOFGikHZ4YqD+Lzv83ZHn1/u6yGenRU1m+KAk9J1GnZMnKcrtfvSktlA1DXNQ==" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.1.0.tgz", + "integrity": "sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA==" }, "node_modules/d3-time-format": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.1.1.tgz", - "integrity": "sha512-8kAkymq2WMfzW7e+s/IUNAtN/y3gZXGRrdGfo6R8NKPAA85UBTxZg5E61bR6nLwjPjj4d3zywSQe1CkYLPFyrw==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.3.0.tgz", + "integrity": "sha512-guv6b2H37s2Uq/GefleCDtbe0XZAuy7Wa49VGkPVPMfLL9qObgBST3lEHJBMUp8S7NdLQAGIvr2KXk8Hc98iKQ==", "dependencies": { "d3-time": "1" } @@ -6460,7 +6469,7 @@ "node_modules/rw": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", - "integrity": "sha1-P4Yt+pGrdmsUiF700BEkv9oHT7Q=" + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" }, "node_modules/rx": { "version": "4.1.0", @@ -8344,14 +8353,6 @@ "node": ">=4" } }, - "node_modules/xmlhttprequest": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz", - "integrity": "sha1-Z/4HXFwk/vOfnWX197f+dRcZaPw=", - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -10489,40 +10490,41 @@ "dev": true }, "d3": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/d3/-/d3-4.13.0.tgz", - "integrity": "sha512-l8c4+0SldjVKLaE2WG++EQlqD7mh/dmQjvi2L2lKPadAVC+TbJC4ci7Uk9bRi+To0+ansgsS0iWfPjD7DBy+FQ==", - "requires": { - "d3-array": "1.2.1", - "d3-axis": "1.0.8", - "d3-brush": "1.0.4", - "d3-chord": "1.0.4", - "d3-collection": "1.0.4", - "d3-color": "1.0.3", - "d3-dispatch": "1.0.3", - "d3-drag": "1.2.1", - "d3-dsv": "1.0.8", - "d3-ease": "1.0.3", - "d3-force": "1.1.0", - "d3-format": "1.2.2", - "d3-geo": "1.9.1", - "d3-hierarchy": "1.1.5", - "d3-interpolate": "1.1.6", - "d3-path": "1.0.5", - "d3-polygon": "1.0.3", - "d3-quadtree": "1.0.3", - "d3-queue": "3.0.7", - "d3-random": "1.1.0", - "d3-request": "1.0.6", - "d3-scale": "1.0.7", - "d3-selection": "1.3.0", - "d3-shape": "1.2.0", - "d3-time": "1.0.8", - "d3-time-format": "2.1.1", - "d3-timer": "1.0.7", - "d3-transition": "1.1.1", - "d3-voronoi": "1.1.2", - "d3-zoom": "1.7.1" + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/d3/-/d3-5.16.0.tgz", + "integrity": "sha512-4PL5hHaHwX4m7Zr1UapXW23apo6pexCgdetdJ5kTmADpG/7T9Gkxw0M0tf/pjoB63ezCCm0u5UaFYy2aMt0Mcw==", + "requires": { + "d3-array": "1", + "d3-axis": "1", + "d3-brush": "1", + "d3-chord": "1", + "d3-collection": "1", + "d3-color": "1", + "d3-contour": "1", + "d3-dispatch": "1", + "d3-drag": "1", + "d3-dsv": "1", + "d3-ease": "1", + "d3-fetch": "1", + "d3-force": "1", + "d3-format": "1", + "d3-geo": "1", + "d3-hierarchy": "1", + "d3-interpolate": "1", + "d3-path": "1", + "d3-polygon": "1", + "d3-quadtree": "1", + "d3-random": "1", + "d3-scale": "2", + "d3-scale-chromatic": "1", + "d3-selection": "1", + "d3-shape": "1", + "d3-time": "1", + "d3-time-format": "2", + "d3-timer": "1", + "d3-transition": "1", + "d3-voronoi": "1", + "d3-zoom": "1" } }, "d3-array": { @@ -10566,6 +10568,14 @@ "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.0.3.tgz", "integrity": "sha1-vHZD/KjlOoNH4vva/6I2eWtYUJs=" }, + "d3-contour": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-1.3.2.tgz", + "integrity": "sha512-hoPp4K/rJCu0ladiH6zmJUEz6+u3lgR+GSm/QdM2BBvDraU39Vr7YdDCicJcxP1z8i9B/2dJLgDC1NcvlF8WCg==", + "requires": { + "d3-array": "^1.1.1" + } + }, "d3-dispatch": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.3.tgz", @@ -10581,9 +10591,9 @@ } }, "d3-dsv": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-1.0.8.tgz", - "integrity": "sha512-IVCJpQ+YGe3qu6odkPQI0KPqfxkhbP/oM1XhhE/DFiYmcXKfCRub4KXyiuehV1d4drjWVXHUWx4gHqhdZb6n/A==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-1.2.0.tgz", + "integrity": "sha512-9yVlqvZcSOMhCYzniHE7EVUws7Fa1zgw+/EAV2BxJoG3ME19V6BQFBwI855XQDsxyOuG7NibqRMTtiF/Qup46g==", "requires": { "commander": "2", "iconv-lite": "0.4", @@ -10595,6 +10605,14 @@ "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.3.tgz", "integrity": "sha1-aL+8NJM4o4DETYrMT7wzBKotjA4=" }, + "d3-fetch": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-1.2.0.tgz", + "integrity": "sha512-yC78NBVcd2zFAyR/HnUiBS7Lf6inSCoWcSxFfw8FYL7ydiqe80SazNwoffcqOfs95XaLo7yebsmQqDKSsXUtvA==", + "requires": { + "d3-dsv": "1" + } + }, "d3-force": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-1.1.0.tgz", @@ -10607,9 +10625,9 @@ } }, "d3-format": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.2.2.tgz", - "integrity": "sha512-zH9CfF/3C8zUI47nsiKfD0+AGDEuM8LwBIP7pBVpyR4l/sKkZqITmMtxRp04rwBrlshIZ17XeFAaovN3++wzkw==" + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.4.5.tgz", + "integrity": "sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ==" }, "d3-geo": { "version": "1.9.1", @@ -10647,41 +10665,33 @@ "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-1.0.3.tgz", "integrity": "sha1-rHmH4+I/6AWpkPKOG1DTj8uCJDg=" }, - "d3-queue": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/d3-queue/-/d3-queue-3.0.7.tgz", - "integrity": "sha1-yTouVLQXwJWRKdfXP2z31Ckudhg=" - }, "d3-random": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-1.1.0.tgz", "integrity": "sha1-ZkLlBsb6OmSFldKyRpeIqNElKdM=" }, - "d3-request": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/d3-request/-/d3-request-1.0.6.tgz", - "integrity": "sha512-FJj8ySY6GYuAJHZMaCQ83xEYE4KbkPkmxZ3Hu6zA1xxG2GD+z6P+Lyp+zjdsHf0xEbp2xcluDI50rCS855EQ6w==", - "requires": { - "d3-collection": "1", - "d3-dispatch": "1", - "d3-dsv": "1", - "xmlhttprequest": "1" - } - }, "d3-scale": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-1.0.7.tgz", - "integrity": "sha512-KvU92czp2/qse5tUfGms6Kjig0AhHOwkzXG0+PqIJB3ke0WUv088AHMZI0OssO9NCkXt4RP8yju9rpH8aGB7Lw==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-2.2.2.tgz", + "integrity": "sha512-LbeEvGgIb8UMcAa0EATLNX0lelKWGYDQiPdHj+gLblGVhGLyNbaCn3EvrJf0A3Y/uOOU5aD6MTh5ZFCdEwGiCw==", "requires": { "d3-array": "^1.2.0", "d3-collection": "1", - "d3-color": "1", "d3-format": "1", "d3-interpolate": "1", "d3-time": "1", "d3-time-format": "2" } }, + "d3-scale-chromatic": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-1.5.0.tgz", + "integrity": "sha512-ACcL46DYImpRFMBcpk9HhtIyC7bTBR4fNOPxwVSl0LfulDAwyiHyPOTqcDG1+t5d4P9W7t/2NAuWu59aKko/cg==", + "requires": { + "d3-color": "1", + "d3-interpolate": "1" + } + }, "d3-selection": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.3.0.tgz", @@ -10696,14 +10706,14 @@ } }, "d3-time": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.0.8.tgz", - "integrity": "sha512-YRZkNhphZh3KcnBfitvF3c6E0JOFGikHZ4YqD+Lzv83ZHn1/u6yGenRU1m+KAk9J1GnZMnKcrtfvSktlA1DXNQ==" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.1.0.tgz", + "integrity": "sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA==" }, "d3-time-format": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.1.1.tgz", - "integrity": "sha512-8kAkymq2WMfzW7e+s/IUNAtN/y3gZXGRrdGfo6R8NKPAA85UBTxZg5E61bR6nLwjPjj4d3zywSQe1CkYLPFyrw==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.3.0.tgz", + "integrity": "sha512-guv6b2H37s2Uq/GefleCDtbe0XZAuy7Wa49VGkPVPMfLL9qObgBST3lEHJBMUp8S7NdLQAGIvr2KXk8Hc98iKQ==", "requires": { "d3-time": "1" } @@ -13918,7 +13928,7 @@ "rw": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", - "integrity": "sha1-P4Yt+pGrdmsUiF700BEkv9oHT7Q=" + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" }, "rx": { "version": "4.1.0", @@ -15477,11 +15487,6 @@ "mkdirp": "^0.5.1" } }, - "xmlhttprequest": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz", - "integrity": "sha1-Z/4HXFwk/vOfnWX197f+dRcZaPw=" - }, "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", diff --git a/src/SmokeTest.Client/MyResponseHandler.cs b/src/SmokeTest.Client/MyResponseHandler.cs new file mode 100644 index 0000000000..e9701f812f --- /dev/null +++ b/src/SmokeTest.Client/MyResponseHandler.cs @@ -0,0 +1,18 @@ +namespace SmokeTest.Client +{ + using System; + using System.Threading.Tasks; + using NServiceBus; + + public class MyResponseHandler : IHandleMessages + { + // remove this pragma after upgrading to NServiceBus 8 +#pragma warning disable PS0018 // A task-returning method should have a CancellationToken parameter unless it has a parameter implementing ICancellableContext + public Task Handle(Response message, IMessageHandlerContext context) +#pragma warning restore PS0018 // A task-returning method should have a CancellationToken parameter unless it has a parameter implementing ICancellableContext + { + Console.WriteLine(@"Response received. Id: {0}", message.Id); + throw new InvalidOperationException(message + "Uh oh...Nulls are bad MK"); + } + } +} \ No newline at end of file diff --git a/src/SmokeTest.Server/MyEventHandler.cs b/src/SmokeTest.Server/MyEventHandler.cs new file mode 100644 index 0000000000..0f422de4d6 --- /dev/null +++ b/src/SmokeTest.Server/MyEventHandler.cs @@ -0,0 +1,17 @@ +namespace SmokeTest.Server.Particular.Core.Deliberately.Insanely.Long.NamespaceToEmulateTheCrazyNamespaceLengthsPeopleGiveNamespacesInTheirSystems +{ + using System; + using System.Threading.Tasks; + using NServiceBus; + + public class MyEventHnd : IHandleMessages + { +#pragma warning disable PS0018 + public Task Handle(MyEvent message, IMessageHandlerContext context) +#pragma warning restore PS0018 + { + Console.WriteLine(@"Evemt received. Id: {0}", message.Id); + return Task.FromResult(0); + } + } +} \ No newline at end of file diff --git a/src/SmokeTest.Server/MyHandler.cs b/src/SmokeTest.Server/MyHandler.cs index a31be05c52..116cbde87d 100644 --- a/src/SmokeTest.Server/MyHandler.cs +++ b/src/SmokeTest.Server/MyHandler.cs @@ -8,14 +8,16 @@ public class MyHandler : IHandleMessages { // remove this pragma after upgrading to NServiceBus 8 #pragma warning disable PS0018 // A task-returning method should have a CancellationToken parameter unless it has a parameter implementing ICancellableContext - public Task Handle(MyMessage message, IMessageHandlerContext context) + public async Task Handle(MyMessage message, IMessageHandlerContext context) #pragma warning restore PS0018 // A task-returning method should have a CancellationToken parameter unless it has a parameter implementing ICancellableContext { Console.WriteLine(@"Message received. Id: {0}", message.Id); + await context.Reply(new Response() { Id = Guid.NewGuid() }).ConfigureAwait(false); + await context.Publish(new MyEvent() { Id = Guid.NewGuid() }).ConfigureAwait(false); if (Program.goodretries || !message.KillMe) { - return Task.FromResult(0); + return; } if (!Program.emulateFailures) @@ -26,8 +28,6 @@ public Task Handle(MyMessage message, IMessageHandlerContext context) { throw new InvalidOperationException(message + "Uh oh...Nulls are bad MK"); } - - return Task.FromResult(0); } static void RandomException(string message) @@ -49,5 +49,4 @@ static void RandomException(string message) } } - } \ No newline at end of file diff --git a/src/SmokeTest.Server/Program.cs b/src/SmokeTest.Server/Program.cs index bd592d7b0c..1a7c3f17dd 100644 --- a/src/SmokeTest.Server/Program.cs +++ b/src/SmokeTest.Server/Program.cs @@ -12,6 +12,7 @@ static async Task Main() endpointConfiguration.UseTransport(); + endpointConfiguration.Recoverability().Immediate(c => c.NumberOfRetries(0)).Delayed(c => c.NumberOfRetries(0)); var enpointInstance = await Endpoint.Start(endpointConfiguration); var exit = false; diff --git a/src/SmokeTest.Shared/MyMessage.cs b/src/SmokeTest.Shared/MyMessage.cs index 31107ff449..74748e849a 100644 --- a/src/SmokeTest.Shared/MyMessage.cs +++ b/src/SmokeTest.Shared/MyMessage.cs @@ -7,4 +7,14 @@ public class MyMessage : IMessage public Guid Id { get; set; } public bool KillMe { get; set; } public string SomeText { get; set; } +} + +public class Response : IMessage +{ + public Guid Id { get; set; } +} + +public class MyEvent : IEvent +{ + public Guid Id { get; set; } } \ No newline at end of file