Merge lp:~michihenning/unity-scopes-api/push-errors into lp:unity-scopes-api

Proposed by Michi Henning
Status: Merged
Approved by: Michal Hruby
Approved revision: 101
Merged at revision: 118
Proposed branch: lp:~michihenning/unity-scopes-api/push-errors
Merge into: lp:unity-scopes-api
Diff against target: 574 lines (+130/-45)
21 files modified
CMakeLists.txt (+1/-1)
debian/changelog (+8/-0)
demo/client.cpp (+20/-6)
demo/scopes/scope-B/scope-B.cpp (+7/-2)
include/scopes/ReceiverBase.h (+5/-3)
include/scopes/Reply.h (+16/-5)
include/scopes/internal/MWReply.h (+1/-1)
include/scopes/internal/ReplyImpl.h (+1/-0)
include/scopes/internal/ReplyObject.h (+1/-1)
include/scopes/internal/zmq_middleware/ZmqReply.h (+1/-1)
src/Reply.cpp (+4/-0)
src/internal/QueryCtrlImpl.cpp (+4/-2)
src/internal/QueryObject.cpp (+3/-3)
src/internal/ReplyImpl.cpp (+36/-3)
src/internal/ReplyObject.cpp (+11/-11)
src/internal/ScopeImpl.cpp (+1/-1)
src/internal/ScopeObject.cpp (+2/-2)
src/internal/zmq_middleware/ReplyI.cpp (+3/-1)
src/internal/zmq_middleware/ZmqReply.cpp (+2/-1)
src/internal/zmq_middleware/capnproto/Reply.capnp (+1/-0)
test/gtest/scopes/Runtime/Runtime_test.cpp (+2/-1)
To merge this branch: bzr merge lp:~michihenning/unity-scopes-api/push-errors
Reviewer Review Type Date Requested Status
Michal Hruby (community) Approve
PS Jenkins bot (community) continuous-integration Approve
Review via email: mp+199601@code.launchpad.net

Commit message

Added ability for scope to push an exception (as an exception_ptr). On the client side,
the exception is delivered as the what() string (if the exception is a std::exception) and
as "unknown exception", otherwise.

Description of the change

Added ability for scope to push an exception (as an exception_ptr). On the client side,
the exception is delivered as the what() string (if the exception is a std::exception) and
as "unknown exception", otherwise.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Michal Hruby (mhr3) wrote :

Hm, thinking more about this, there is pretty much nothing a client can do with the message in the finished() method, so I'm wondering whether it should really be there.

A much nicer API would be if create_query() returned a future and you could get() the operation result from there - and it could even throw an error at that point.

Revision history for this message
Michal Hruby (mhr3) wrote :

Of course that doesn't change the fact the error should be tranferred on the protocol level.

Revision history for this message
Michi Henning (michihenning) wrote :

I could remove the message in the finished() method on the server side, but I think James wanted to have this for the Go binding (which is why I added it in the first place).

I agree, the client can't do all that much with it. But, in James's case, he needs the error for testing, to see whether Go errors are correctly propagated across to C++. (James, correct me please if I got that wrong.)

Michal, if you recall, when you first pushed for this, it was *me* who argued that an error flag is good enough for the Dash because the Dash can't do much useful with the error message either :-)

It looks like we can't have our cake and eat it too. And I'd rather not pollute the public API with methods that are there purely for testing.

We could make a derived version of the interface for testing that provides access to the extra parameter, but it adds yet complexity.

Does anyone else have a bright idea?

I think I could return a future in addition to the CtrlProxy. But I'm not sure that this would necessarily work better. Results can arrive at any time (push, cancel, finished, or error), and there can be multiple pushes. A future is a one-shot API, effectively saying "wait for finish or exception".

Hmmm... Michal, you are sitting at the receiving end of the API. Would providing a future make more sense than the current finished() and error() callbacks? If an error is recorded, the future would return something like a ScopeException with an error string, regardless of the actual exception that was caught on the scope side. That's because I can't marshal arbitrary exceptions back over the wire.

I can add a future, but I'd like to do this only if there is a compelling reason. Doing so will make create_query() more complicated because it then would have two return values. (Or I overload create_query() to make the return of the future optional, but that's also more complex.)

The current callback API has the advantage that it is very simple and that C++ programmers of moderate skill level will have no problem understanding it. On the other hand, there are many C++ programmers whose eyes glaze over as soon as you mention std::future...

Revision history for this message
Michal Hruby (mhr3) wrote :

Well, for UI-programming futures suck, cause they block the thread :) Plus having a dedicated thread just to allow it to run each future's get sounds expensive. Moreover we do want to get the partial resultsets as soon as possible - so the virtual push() is nice. That being said, with all the threading in place, you could actually end up processing finished() before processing last push(), and that'd be bad. But I'm getting sidetracked.

I can see that futures would simplify aggregating scopes, and being able to start the query and wait for it to finish + get potential exception in the same place is really nice, and ultimately will be what you end up doing "manually" if there's no future.

So bottomline, I don't see a silver bullet, both approaches have their pros and cons.

Revision history for this message
Michi Henning (michihenning) wrote :

I think it's probably better, on balance, to leave it as is. It's easy enough for the scope author to use a promise/future or a condvar if they want to wait for completion.

Michal, if you can live with that, can you approve please?

99. By Michi Henning

Merged trunk and resolved conflict.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Michal Hruby (mhr3) wrote :

18 +unity-scopes-api (0.1.7+14.04.20131219.1-0ubuntu2) UNRELEASED; urgency=low

No need to change the -0ubuntuX suffix.

20 + [ michi ]
25 + -- michi <michi@djembefola> Thu, 02 Jan 2014 16:10:06 +1000

Could you please create ~/.devscripts with the content:
<email address hidden>
DEBFULLNAME=Your name

With that dch will produce a proper changelog entry. Also there's no need for the [Name] line, dch will do that automatically when there are multiple authors.

537 +#include <iostream> // TODO: remove this
555 +cerr << "sending error reply: " << error_message << endl;

Forgotten debug?

review: Needs Fixing
100. By Michi Henning

Removed left-over debug trace.

Revision history for this message
Michi Henning (michihenning) wrote :

> 18 +unity-scopes-api (0.1.7+14.04.20131219.1-0ubuntu2) UNRELEASED;
> urgency=low
>
> No need to change the -0ubuntuX suffix.

OK, thanks for that. So, what should I do when I commit something? (Sorry, but the whole debian thing is still a bit of mystery to me.)

> 20 + [ michi ]
> 25 + -- michi <michi@djembefola> Thu, 02 Jan 2014 16:10:06 +1000
>
> Could you please create ~/.devscripts with the content:
> <email address hidden>
> DEBFULLNAME=Your name
>
> With that dch will produce a proper changelog entry. Also there's no need for
> the [Name] line, dch will do that automatically when there are multiple
> authors.

OK, I just did that, thanks!

> 537 +#include <iostream> // TODO: remove this
> 555 +cerr << "sending error reply: " << error_message << endl;
>
> Forgotten debug?

Yes, thanks for spotting this! I've just committed with this removed. Hopefully, that'll be OK this time.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Michal Hruby (mhr3) wrote :

> OK, thanks for that. So, what should I do when I commit something? (Sorry, but
> the whole debian thing is still a bit of mystery to me.)

So, when changing API, you bump the version number as you did:
8 -set(UNITY_SCOPES_MICRO 6)
9 +set(UNITY_SCOPES_MICRO 7)

Then you run `dch -v "[new-version]-0ubuntu1"`. Ie `dch -v "0.1.7-0ubuntu1"` in this case.

That will create a new changelog entry where you just add the message, nothing else. Plus with the correct DEB* variables as mentioned above, it'll use your real name and email, not just username@hostname as is visible here (michi@djembefola, is that a real DJ btw? :))

So can you please revert the changelog change and do it again to fix it?

Revision history for this message
Michal Hruby (mhr3) wrote :

> So can you please revert the changelog change and do it again to fix it?

Just to clarify, no need for VCS revert, just delete the new entry and run "dch ..." again.

101. By Michi Henning

Fixed changelog yet again.

Revision history for this message
Michi Henning (michihenning) wrote :

> Then you run `dch -v "[new-version]-0ubuntu1"`. Ie `dch -v "0.1.7-0ubuntu1"`
> in this case.
>
> That will create a new changelog entry where you just add the message, nothing
> else. Plus with the correct DEB* variables as mentioned above, it'll use your
> real name and email, not just username@hostname as is visible here

Thanks for that! I've just pushed this. It looks like dch is ignoring what's in my .devscripts file. Here are the contents:

<email address hidden>
DEBFULLNAME="Michi Henning"

When I run

dch -v "0.1.7-0ubuntu1"

I get the following at the bottom:

-- Michi Henning <michi@djembefola> Fri, 03 Jan 2014 07:35:43 +1000

DEBEMAIL is being ignored, it seems. I've verified that .devscripts is being read by adding a syntax error. When I do that, I get an error message. So it's not that the file has the wrong name or is in the wrong place.

When I set this as an environment variable instead, it works, so I've set it up in my .bashrc now.

> (michi@djembefola, is that a real DJ btw? :))

:-)

"Djembefola" is a Malinke word. "Fola" means to "play an instrument". So a djembefola literally means "one who plays the djembe". It's the name of my desktop machine :-)

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Michal Hruby (mhr3) wrote :

> -- Michi Henning <michi@djembefola> Fri, 03 Jan 2014 07:35:43 +1000
>
> DEBEMAIL is being ignored, it seems. I've verified that .devscripts is being
> read by adding a syntax error. When I do that, I get an error message. So it's
> not that the file has the wrong name or is in the wrong place.
>
> When I set this as an environment variable instead, it works, so I've set it
> up in my .bashrc now.

Ah, you're right indeed, I have it also both in my ~/.devscripts and ~/.bashrc

> > (michi@djembefola, is that a real DJ btw? :))
>
> :-)
>
> "Djembefola" is a Malinke word. "Fola" means to "play an instrument". So a
> djembefola literally means "one who plays the djembe". It's the name of my
> desktop machine :-)

I see, so not exactly a DJ, but close :)

review: Approve
Revision history for this message
Michi Henning (michihenning) wrote :

Aargh... :-(

I think the version should now be 8 because that was an incompatible ABI change. That's a problem when there is more than one branch outstanding that touches the API.

Michal, could you check please and perform whatever requisite magic we need?

Revision history for this message
Michal Hruby (mhr3) wrote :

> Aargh... :-(
>
> I think the version should now be 8 because that was an incompatible ABI
> change. That's a problem when there is more than one branch outstanding that
> touches the API.
>
> Michal, could you check please and perform whatever requisite magic we need?

Right, but there are no other approved branches which would bump the version number, so it's fine (we don't care about strict ABI compatibility just yet). But of course other branches which again change the API will need to be bumped to 8.

Revision history for this message
Michi Henning (michihenning) wrote :

> Right, but there are no other approved branches which would bump the version
> number, so it's fine (we don't care about strict ABI compatibility just yet).

Phew! :-)

> But of course other branches which again change the API will need to be bumped
> to 8.

We have a more general problem here: suppose we are at version 7. I make an incompatible change in an MR and dutifully bump the version to 8. The MR hangs around for a few days (like some just did because of the Christmas break.) Then I fix something else that's incompatible and also dutifully bump the version to 8. (Or, more likely, someone else does.) Now we have two incompatible changes, but only one version increment :-(

Depending when the branches get merged, there is a window where someone will get bitten :-(

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2013-12-27 02:52:30 +0000
3+++ CMakeLists.txt 2014-01-02 21:33:37 +0000
4@@ -150,7 +150,7 @@
5 # API version
6 set(UNITY_SCOPES_MAJOR 0)
7 set(UNITY_SCOPES_MINOR 1)
8-set(UNITY_SCOPES_MICRO 6)
9+set(UNITY_SCOPES_MICRO 7)
10
11 # Scopes library
12 set(UNITY_SCOPES_LIB unity-scopes)
13
14=== modified file 'debian/changelog'
15--- debian/changelog 2013-12-19 21:08:02 +0000
16+++ debian/changelog 2014-01-02 21:33:37 +0000
17@@ -1,3 +1,11 @@
18+unity-scopes-api (0.1.7-0ubuntu1) UNRELEASED; urgency=low
19+
20+ * Added ability for scope to push an exception (as an exception_ptr). On the client side,
21+ the exception is delivered as the what() string (if the exception is a std::exception) and
22+ as "unknown exception", otherwise.
23+
24+ -- Michi Henning <michi.henning@canonical.com> Fri, 03 Jan 2014 07:31:02 +1000
25+
26 unity-scopes-api (0.1.6+14.04.20131219.1-0ubuntu1) trusty; urgency=low
27
28 [ Pawel Stolowski ]
29
30=== modified file 'demo/client.cpp'
31--- demo/client.cpp 2013-12-16 07:05:08 +0000
32+++ demo/client.cpp 2014-01-02 21:33:37 +0000
33@@ -40,28 +40,42 @@
34
35 virtual void push(Category::SCPtr category) override
36 {
37- cout << "received category: id=" << category->id() << " title=" << category->title() << " icon=" << category->icon() << " template=" <<
38- category->renderer_template().data() << endl;
39+ cout << "received category: id=" << category->id()
40+ << " title=" << category->title()
41+ << " icon=" << category->icon()
42+ << " template=" << category->renderer_template().data()
43+ << endl;
44 }
45
46 virtual void push(CategorisedResult result) override
47 {
48- cout << "received result: uri=" << result.uri() << " title=" << result.title() << " category id: " << result.category()->id() << endl;
49+ cout << "received result: uri=" << result.uri()
50+ << " title=" << result.title()
51+ << " category id: "
52+ << result.category()->id()
53+ << endl;
54 }
55
56 virtual void push(Annotation annotation) override
57 {
58 auto links = annotation.links();
59- cout << "received annotation of type " << annotation.annotation_type() << " with " << links.size() << " link(s):" << endl;
60+ cout << "received annotation of type " << annotation.annotation_type()
61+ << " with " << links.size() << " link(s):"
62+ << endl;
63 for (auto link: links)
64 {
65 cout << " " << link->query().to_string() << endl;
66 }
67 }
68
69- virtual void finished(ReceiverBase::Reason reason) override
70+ virtual void finished(ReceiverBase::Reason reason, string const& error_message) override
71 {
72- cout << "query complete, status: " << to_string(reason) << endl;
73+ cout << "query complete, status: " << to_string(reason);
74+ if (reason == ReceiverBase::Error)
75+ {
76+ cout << ": " << error_message;
77+ }
78+ cout << endl;
79 {
80 unique_lock<decltype(mutex_)> lock(mutex_);
81 query_complete_ = true;
82
83=== modified file 'demo/scopes/scope-B/scope-B.cpp'
84--- demo/scopes/scope-B/scope-B.cpp 2013-12-04 12:00:33 +0000
85+++ demo/scopes/scope-B/scope-B.cpp 2014-01-02 21:33:37 +0000
86@@ -57,9 +57,14 @@
87 }
88 }
89
90- virtual void finished(Reason reason) override
91+ virtual void finished(Reason reason, string const& error_message) override
92 {
93- cout << "query to " << scope_name_ << " complete, status: " << to_string(reason) << endl;
94+ cout << "query to " << scope_name_ << " complete, status: " << to_string(reason);
95+ if (reason == ReceiverBase::Error)
96+ {
97+ cout << ": " << error_message;
98+ }
99+ cout << endl;
100 }
101
102 Receiver(string const& scope_name, ReplyProxy const& upstream) :
103
104=== modified file 'include/scopes/ReceiverBase.h'
105--- include/scopes/ReceiverBase.h 2013-12-27 03:32:57 +0000
106+++ include/scopes/ReceiverBase.h 2014-01-02 21:33:37 +0000
107@@ -84,8 +84,8 @@
108 /**
109 \brief Indicates the cause of a call to finished().
110 The Error enumerator indicates that a query terminated abnormally, for example,
111- because a scope could not be reached over the network or terminated an query
112- abnormally.
113+ because a scope could not be reached over the network, a query terminated
114+ abnormally, or explicitly reported an error.
115 */
116 enum Reason { Finished, Cancelled, Error };
117
118@@ -93,8 +93,10 @@
119 \brief Called once by the scopes run time after the final result for a query() was sent.
120 Exceptions thrown from finished() are ignored.
121 \param r Indicates the cause for the call to finished().
122+ \param error_message If r is set to Reason::Error, error_message contains further details.
123+ Otherwise, error_message is the empty string.
124 */
125- virtual void finished(Reason r) = 0;
126+ virtual void finished(Reason r, std::string const& error_message) = 0;
127
128 protected:
129 /// @cond
130
131=== modified file 'include/scopes/Reply.h'
132--- include/scopes/Reply.h 2013-12-05 12:20:08 +0000
133+++ include/scopes/Reply.h 2014-01-02 21:33:37 +0000
134@@ -55,13 +55,15 @@
135 \brief Create and register a new Category. The category is automatically sent to the source of the query.
136 \return Category instance
137 */
138- Category::SCPtr register_category(std::string const& id, std::string const& title, std::string const &icon, CategoryRenderer const& renderer_template =
139- CategoryRenderer());
140+ Category::SCPtr register_category(std::string const& id,
141+ std::string const& title,
142+ std::string const &icon,
143+ CategoryRenderer const& renderer_template = CategoryRenderer());
144
145 /**
146 \brief Register an existing category instance and send it to the source of the query.
147- The purpose of this call is to register a category obtained via ReplyBase::push(Category::SCPtr) when aggregating results and categories from
148- other scope(s).
149+ The purpose of this call is to register a category obtained via ReplyBase::push(Category::SCPtr) when aggregating
150+ results and categories from other scope(s).
151 */
152 void register_category(Category::SCPtr category);
153
154@@ -89,13 +91,22 @@
155 was sent, that is, that the query is complete.
156 The scope application code is responsible for calling finished() once it has sent the
157 final result for a query.
158- Multiple calls to finished() are ignored.
159+ Multiple calls to finished() and calls to error() after finished() was called are ignored.
160 The destructor implicitly calls finished() if a Reply goes out of scope without
161 a prior call to finished().
162 */
163 void finished() const;
164
165 /**
166+ \brief Informs the source of a query that the query was terminated due to an error.
167+ Multiple calls to error() and calls to finished() after error() was called are ignored.
168+ \param ex An exception_ptr indicating the cause of the error. If ex is a `std::exception`,
169+ the return value of `what()` is made available to the query source. Otherwise,
170+ the query source receives `"unknown exception"`.
171+ */
172+ void error(std::exception_ptr ex) const;
173+
174+ /**
175 \brief Destroys a Reply.
176 If a Reply goes out of scope without a prior call to finished(), the destructor implicitly calls finished().
177 */
178
179=== modified file 'include/scopes/internal/MWReply.h'
180--- include/scopes/internal/MWReply.h 2013-11-25 19:05:41 +0000
181+++ include/scopes/internal/MWReply.h 2014-01-02 21:33:37 +0000
182@@ -44,7 +44,7 @@
183 virtual ~MWReply() noexcept;
184
185 virtual void push(VariantMap const& result) = 0;
186- virtual void finished(ReceiverBase::Reason reason) = 0;
187+ virtual void finished(ReceiverBase::Reason reason, std::string const& error_message) = 0;
188
189 protected:
190 MWReply(MiddlewareBase* mw_base);
191
192=== modified file 'include/scopes/internal/ReplyImpl.h'
193--- include/scopes/internal/ReplyImpl.h 2013-12-05 12:20:08 +0000
194+++ include/scopes/internal/ReplyImpl.h 2014-01-02 21:33:37 +0000
195@@ -66,6 +66,7 @@
196 bool push(unity::api::scopes::Annotation const& annotation);
197 void finished();
198 void finished(unity::api::scopes::ReceiverBase::Reason reason);
199+ void error(std::exception_ptr ex);
200
201 static ReplyProxy create(MWReplyProxy const& mw_proxy, std::shared_ptr<QueryObject> const& qo);
202
203
204=== modified file 'include/scopes/internal/ReplyObject.h'
205--- include/scopes/internal/ReplyObject.h 2013-11-25 19:05:41 +0000
206+++ include/scopes/internal/ReplyObject.h 2014-01-02 21:33:37 +0000
207@@ -56,7 +56,7 @@
208
209 // Remote operation implementations
210 void push(VariantMap const& result) noexcept;
211- void finished(ReceiverBase::Reason reason) noexcept;
212+ void finished(ReceiverBase::Reason reason, std::string const& error_message) noexcept;
213
214 private:
215 ReceiverBase::SPtr const receiver_base_;
216
217=== modified file 'include/scopes/internal/zmq_middleware/ZmqReply.h'
218--- include/scopes/internal/zmq_middleware/ZmqReply.h 2013-11-25 19:05:41 +0000
219+++ include/scopes/internal/zmq_middleware/ZmqReply.h 2014-01-02 21:33:37 +0000
220@@ -45,7 +45,7 @@
221 virtual ~ZmqReply() noexcept;
222
223 virtual void push(VariantMap const& result) override;
224- virtual void finished(ReceiverBase::Reason reason) override;
225+ virtual void finished(ReceiverBase::Reason reason, std::string const& error_message) override;
226 };
227
228 } // namespace zmq_middleware
229
230=== modified file 'src/Reply.cpp'
231--- src/Reply.cpp 2013-12-05 12:20:08 +0000
232+++ src/Reply.cpp 2014-01-02 21:33:37 +0000
233@@ -73,6 +73,10 @@
234 return fwd()->finished();
235 }
236
237+void Reply::error(std::exception_ptr ex) const
238+{
239+ return fwd()->error(ex);
240+}
241 internal::ReplyImpl* Reply::fwd() const
242 {
243 return dynamic_cast<internal::ReplyImpl*>(pimpl());
244
245=== modified file 'src/internal/QueryCtrlImpl.cpp'
246--- src/internal/QueryCtrlImpl.cpp 2013-11-25 19:05:41 +0000
247+++ src/internal/QueryCtrlImpl.cpp 2014-01-02 21:33:37 +0000
248@@ -26,6 +26,7 @@
249 #include <scopes/ScopeExceptions.h>
250
251 #include <cassert>
252+#include <iostream> // TODO: remove this once logging is added
253
254 using namespace std;
255
256@@ -65,10 +66,11 @@
257 // Indicate (to ourselves) that this query is complete. Calling via the MWReplyProxy ensures
258 // the finished() call will be processed by a seperate server-side thread,
259 // so we cannot block here.
260- reply_proxy_->finished(ReceiverBase::Cancelled);
261+ reply_proxy_->finished(ReceiverBase::Cancelled, "");
262 }
263- catch (MiddlewareException const& e)
264+ catch (std::exception const& e)
265 {
266+ cerr << e.what() << endl;
267 // TODO: log error
268 }
269 }
270
271=== modified file 'src/internal/QueryObject.cpp'
272--- src/internal/QueryObject.cpp 2013-12-13 04:48:38 +0000
273+++ src/internal/QueryObject.cpp 2014-01-02 21:33:37 +0000
274@@ -94,15 +94,15 @@
275 catch (std::exception const& e)
276 {
277 pushable_ = false;
278- reply_->finished(ReceiverBase::Error); // Oneway, can't block
279 // TODO: log error
280+ reply_->finished(ReceiverBase::Error, e.what()); // Oneway, can't block
281 cerr << "ScopeBase::run(): " << e.what() << endl;
282 }
283 catch (...)
284 {
285 pushable_ = false;
286- reply_->finished(ReceiverBase::Error); // Oneway, can't block
287 // TODO: log error
288+ reply_->finished(ReceiverBase::Error, "unknown exception"); // Oneway, can't block
289 cerr << "ScopeBase::run(): unknown exception" << endl;
290 }
291 }
292@@ -116,7 +116,7 @@
293 // Send finished() to up-stream client to tell him the query is done.
294 // We send via the MWReplyProxy here because that allows passing
295 // a ReceiverBase::Reason (whereas the public ReplyProxy does not).
296- reply_->finished(ReceiverBase::Cancelled); // Oneway, can't block
297+ reply_->finished(ReceiverBase::Cancelled, ""); // Oneway, can't block
298 }
299
300 // Forward the cancellation to the query base (which in turn will forward it to any subqueries).
301
302=== modified file 'src/internal/ReplyImpl.cpp'
303--- src/internal/ReplyImpl.cpp 2013-12-06 11:22:12 +0000
304+++ src/internal/ReplyImpl.cpp 2014-01-02 21:33:37 +0000
305@@ -30,6 +30,7 @@
306
307 #include <sstream>
308 #include <cassert>
309+#include <iostream> // TODO: remove this once logging is added
310
311 using namespace std;
312
313@@ -73,7 +74,10 @@
314 push(category);
315 }
316
317-Category::SCPtr ReplyImpl::register_category(std::string const& id, std::string const& title, std::string const &icon, CategoryRenderer const& renderer_template)
318+Category::SCPtr ReplyImpl::register_category(std::string const& id,
319+ std::string const& title,
320+ std::string const &icon,
321+ CategoryRenderer const& renderer_template)
322 {
323 auto cat = cat_registry_->register_category(id, title, icon, renderer_template); // will throw if adding same category again
324
325@@ -139,7 +143,7 @@
326 catch (MiddlewareException const& e)
327 {
328 // TODO: log error
329- finished(ReceiverBase::Error);
330+ error(current_exception());
331 return false;
332 }
333 }
334@@ -157,15 +161,44 @@
335 {
336 try
337 {
338- fwd()->finished(reason);
339+ fwd()->finished(reason, "");
340 }
341 catch (MiddlewareException const& e)
342 {
343 // TODO: log error
344+ cerr << e.what() << endl;
345 }
346 }
347 }
348
349+void ReplyImpl::error(exception_ptr ex)
350+{
351+ string error_message;
352+ try
353+ {
354+ rethrow_exception(ex);
355+ }
356+ catch (std::exception const& e)
357+ {
358+ error_message = e.what();
359+ }
360+ catch (...)
361+ {
362+ error_message = "unknown exception";
363+ }
364+
365+ try
366+ {
367+ fwd()->finished(ReceiverBase::Error, error_message);
368+ }
369+ catch (MiddlewareException const& e)
370+ {
371+ // TODO: log error
372+ cerr << e.what() << endl;
373+ }
374+}
375+
376+
377 ReplyProxy ReplyImpl::create(MWReplyProxy const& mw_proxy, std::shared_ptr<QueryObject> const& qo)
378 {
379 return ReplyProxy(new Reply((new ReplyImpl(mw_proxy, qo))));
380
381=== modified file 'src/internal/ReplyObject.cpp'
382--- src/internal/ReplyObject.cpp 2013-12-17 01:39:35 +0000
383+++ src/internal/ReplyObject.cpp 2014-01-02 21:33:37 +0000
384@@ -22,7 +22,6 @@
385 #include <scopes/ReceiverBase.h>
386 #include <scopes/Category.h>
387 #include <scopes/CategorisedResult.h>
388-#include <unity/Exception.h>
389
390 #include <cassert>
391 #include <iostream> // TODO: remove this once logging is added
392@@ -57,7 +56,7 @@
393 {
394 try
395 {
396- finished(ReceiverBase::Finished);
397+ finished(ReceiverBase::Finished, "");
398 }
399 catch (...)
400 {
401@@ -110,10 +109,11 @@
402 Annotation annotation(new internal::AnnotationImpl(*cat_registry_, result_var));
403 receiver_base_->push(std::move(annotation));
404 }
405- catch (unity::Exception const& e)
406+ catch (std::exception const& e)
407 {
408- // TODO: this is an internal error; log error
409- finished(ReceiverBase::Error);
410+ // TODO: log this
411+ cerr << "ReplyObject::receiver_base_->push(): " << e.what() << endl;
412+ finished(ReceiverBase::Error, e.what());
413 }
414 }
415
416@@ -128,9 +128,9 @@
417 }
418 catch (std::exception const& e)
419 {
420- // TODO: this is an internal error; log error
421+ // TODO: log this
422 cerr << "ReplyObject::receiver_base_->push(): " << e.what() << endl;
423- finished(ReceiverBase::Error);
424+ finished(ReceiverBase::Error, e.what());
425 }
426 }
427 }
428@@ -140,7 +140,7 @@
429 cerr << "ReplyObject::push(VariantMap): " << e.what() << endl;
430 try
431 {
432- finished(ReceiverBase::Error);
433+ finished(ReceiverBase::Error, e.what());
434 }
435 catch (...)
436 {
437@@ -152,7 +152,7 @@
438 cerr << "ReplyObject::push(VariantMap): unknown exception" << endl;
439 try
440 {
441- finished(ReceiverBase::Error);
442+ finished(ReceiverBase::Error, "unknown exception");
443 }
444 catch (...)
445 {
446@@ -165,7 +165,7 @@
447 }
448 }
449
450-void ReplyObject::finished(ReceiverBase::Reason r) noexcept
451+void ReplyObject::finished(ReceiverBase::Reason r, string const& error_message) noexcept
452 {
453 // We permit exactly one finished() call for a query. This avoids
454 // a race condition where the executing down-stream query invokes
455@@ -188,7 +188,7 @@
456 lock.unlock(); // Inform the application code that the query is complete outside synchronization.
457 try
458 {
459- receiver_base_->finished(r);
460+ receiver_base_->finished(r, error_message);
461 }
462 catch (std::exception const& e)
463 {
464
465=== modified file 'src/internal/ScopeImpl.cpp'
466--- src/internal/ScopeImpl.cpp 2013-12-13 04:48:38 +0000
467+++ src/internal/ScopeImpl.cpp 2014-01-02 21:33:37 +0000
468@@ -79,7 +79,7 @@
469 {
470 // TODO: if things go wrong, we need to make sure that the reply object
471 // is disconnected from the middleware, so it gets deallocated.
472- reply->finished(ReceiverBase::Error);
473+ reply->finished(ReceiverBase::Error, e.what());
474 throw;
475 }
476 catch (...)
477
478=== modified file 'src/internal/ScopeObject.cpp'
479--- src/internal/ScopeObject.cpp 2013-12-13 04:48:38 +0000
480+++ src/internal/ScopeObject.cpp 2014-01-02 21:33:37 +0000
481@@ -123,7 +123,7 @@
482 {
483 try
484 {
485- reply->finished(ReceiverBase::Error);
486+ reply->finished(ReceiverBase::Error, e.what());
487 }
488 catch (...)
489 {
490@@ -136,7 +136,7 @@
491 {
492 try
493 {
494- reply->finished(ReceiverBase::Error);
495+ reply->finished(ReceiverBase::Error, "unknown exception");
496 }
497 catch (...)
498 {
499
500=== modified file 'src/internal/zmq_middleware/ReplyI.cpp'
501--- src/internal/zmq_middleware/ReplyI.cpp 2013-12-12 16:02:06 +0000
502+++ src/internal/zmq_middleware/ReplyI.cpp 2014-01-02 21:33:37 +0000
503@@ -81,6 +81,7 @@
504 auto req = in_params.getAs<capnproto::Reply::FinishedRequest>();
505 auto r = req.getReason();
506 ReceiverBase::Reason reason;
507+ string err;
508 switch (r)
509 {
510 case capnproto::Reply::FinishedReason::FINISHED:
511@@ -96,6 +97,7 @@
512 case capnproto::Reply::FinishedReason::ERROR:
513 {
514 reason = ReceiverBase::Error;
515+ err = req.getError();
516 break;
517 }
518 default:
519@@ -104,7 +106,7 @@
520 reason = ReceiverBase::Error; // LCOV_EXCL_LINE
521 }
522 }
523- delegate->finished(reason);
524+ delegate->finished(reason, err);
525 }
526
527 } // namespace zmq_middleware
528
529=== modified file 'src/internal/zmq_middleware/ZmqReply.cpp'
530--- src/internal/zmq_middleware/ZmqReply.cpp 2013-12-02 18:10:46 +0000
531+++ src/internal/zmq_middleware/ZmqReply.cpp 2014-01-02 21:33:37 +0000
532@@ -71,7 +71,7 @@
533 future.wait();
534 }
535
536-void ZmqReply::finished(ReceiverBase::Reason reason)
537+void ZmqReply::finished(ReceiverBase::Reason reason, string const& error_message)
538 {
539 capnp::MallocMessageBuilder request_builder;
540 auto request = make_request_(request_builder, "finished");
541@@ -92,6 +92,7 @@
542 case ReceiverBase::Error:
543 {
544 r = capnproto::Reply::FinishedReason::ERROR;
545+ in_params.setError(error_message);
546 break;
547 }
548 default:
549
550=== modified file 'src/internal/zmq_middleware/capnproto/Reply.capnp'
551--- src/internal/zmq_middleware/capnproto/Reply.capnp 2013-11-22 04:00:45 +0000
552+++ src/internal/zmq_middleware/capnproto/Reply.capnp 2014-01-02 21:33:37 +0000
553@@ -54,4 +54,5 @@
554 struct FinishedRequest
555 {
556 reason @0 : FinishedReason;
557+ error @1 : Text; # Present only if reason is error
558 }
559
560=== modified file 'test/gtest/scopes/Runtime/Runtime_test.cpp'
561--- test/gtest/scopes/Runtime/Runtime_test.cpp 2013-12-06 10:42:26 +0000
562+++ test/gtest/scopes/Runtime/Runtime_test.cpp 2014-01-02 21:33:37 +0000
563@@ -53,9 +53,10 @@
564 EXPECT_EQ("dnd_uri", result.dnd_uri());
565 count_++;
566 }
567- virtual void finished(ReceiverBase::Reason reason) override
568+ virtual void finished(ReceiverBase::Reason reason, string const& error_message) override
569 {
570 EXPECT_EQ(Finished, reason);
571+ EXPECT_EQ("", error_message);
572 EXPECT_EQ(1, count_);
573 // Signal that the query has completed.
574 unique_lock<mutex> lock(mutex_);

Subscribers

People subscribed via source and target branches

to all changes: