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.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 @@
+
{{ 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