Skip to content
Snippets Groups Projects
Commit bf180b0f authored by Michael Davis's avatar Michael Davis
Browse files

[EOS-CTA] Converts exceptions into Alerts on client side

The framework does not throw exceptions to the client, instead it puts
the exception in an Alert and calls the AlertCallback to log it.
parent b1a8321f
No related branches found
No related tags found
No related merge requests found
......@@ -69,6 +69,21 @@ void RequestCallback<eos::wfe::Alert>::operator()(const eos::wfe::Alert &alert)
OutputJsonString(&alert);
}
/*!
* Convert exceptions into Alerts.
*
* This tells the framework how to log exceptions received on the client side
*/
template<>
void ExceptionToAlert<eos::wfe::Alert>::operator()(const std::exception &e, eos::wfe::Alert &alert)
{
alert.set_audience(eos::wfe::Alert::EOSLOG);
alert.set_message_txt(e.what());
}
} // namespace XrdSsiPb
......@@ -299,7 +314,7 @@ int exceptionThrowingMain(int argc, const char *const *const argv)
std::cout << "Request sent, going to sleep..." << std::endl;
int wait_secs = 5;
int wait_secs = 20;
while(wait_secs--)
{
......
......@@ -40,7 +40,7 @@ message Security {
message Alert {
enum Audience { EOSLOG = 0; ENDUSER = 1; }
Audience audience = 1; //< The intended audience of the error message
string message = 2; //< An empty if success, else an error message
string message_txt = 2; //< An empty if success, else an error message
}
......
......@@ -154,16 +154,14 @@ void RequestProc<eos::wfe::Notification, eos::wfe::Response, eos::wfe::Alert>::E
template <>
void RequestProc<eos::wfe::Notification, eos::wfe::Response, eos::wfe::Alert>::ExecuteAlerts()
{
// Allocate alert messages on the heap, they are self-destructing
eos::wfe::Alert alert_msg;
auto *alert_msg = new eos::wfe::Alert();
alert_msg.set_audience(eos::wfe::Alert::EOSLOG);
alert_msg.set_message_txt("Something bad happened");
alert_msg->set_audience(eos::wfe::Alert::EOSLOG);
alert_msg->set_message("Something bad happened");
// Serialize and send the alert message
// Send the alert message
Alert(*alert_msg);
Alert(alert_msg);
}
......@@ -187,7 +185,7 @@ void RequestProc<eos::wfe::Notification, eos::wfe::Response, eos::wfe::Alert>::
//case PB_PARSE_ERR: m_metadata.mutable_exception()->set_code(eos::wfe::Exception::PB_PARSE_ERR);
//}
m_metadata.mutable_alert_msg()->set_message(err_text);
m_metadata.mutable_alert_msg()->set_message_txt(err_text);
// Output message in Json format (for debugging)
......
......@@ -26,7 +26,7 @@ namespace XrdSsiPb {
/*!
* XRootD SSI + Protocol Buffers Callback class
*
* The client should specialize on this class for each XRootD reply type (Metadata, Alert, Error)
* The client should specialize on this class for each XRootD reply type (Metadata, Alert)
*/
template<typename CallbackArg>
......@@ -38,6 +38,21 @@ public:
/*!
* Convert Exceptions to Alerts
*
* The client should specialize on this class to specify how to log exceptions
*/
template<typename AlertType>
class ExceptionToAlert
{
public:
void operator()(const std::exception &e, AlertType &alert);
};
/*!
* XRootD SSI + Protocol Buffers Request class
*/
......@@ -100,16 +115,21 @@ public:
virtual XrdSsiRequest::PRD_Xeq ProcessResponseData(const XrdSsiErrInfo &eInfo, char *buff, int blen, bool last) override;
/*!
* The Alert method is optional. By default, Alert messages are ignored.
* Deserialize Alert messages and call the Alert callback
*/
virtual void Alert(XrdSsiRespInfoMsg &aMsg) override;
virtual void Alert(XrdSsiRespInfoMsg &alert_msg) override;
private:
const char *m_request_bufptr; //!< Pointer to the Request buffer
int m_request_len; //!< Size of the Request buffer
int m_response_bufsize; //!< Size of the Response buffer
// Convert exceptions to Alerts. Must be defined on the client side.
ExceptionToAlert<AlertType> ExceptionHandler;
// Callbacks for each of the XRootD reply types
RequestCallback<MetadataType> MetadataCallback;
......@@ -136,40 +156,26 @@ bool Request<RequestType, MetadataType, AlertType>::ProcessResponse(const XrdSsi
std::cout << "[DEBUG] ProcessResponse(): response type = " << rInfo.State() << std::endl;
#endif
switch(rInfo.rType)
{
try {
switch(rInfo.rType) {
// Handle errors in the XRootD framework (e.g. no response from server)
case XrdSsiRespInfo::isError:
//ErrorCallback(eInfo.Get());
Finished(); // Return control of the object to the calling thread and delete rInfo
// Andy says it is now safe to delete the Request object, which implies that the pointer on the calling side
// will never refer to it again and the destructor of the base class doesn't access any class members.
delete this;
break;
case XrdSsiRespInfo::isHandle:
// To implement detached requests, add another callback type which saves the handle
//ErrorCallback("Detached requests are not implemented.");
Finished();
delete this;
break;
case XrdSsiRespInfo::isFile:
// To implement file requests, add another callback type
//ErrorCallback("File requests are not implemented.");
Finished();
delete this;
break;
case XrdSsiRespInfo::isStream:
// To implement stream requests, add another callback type
//ErrorCallback("Stream requests are not implemented.");
Finished();
delete this;
break;
case XrdSsiRespInfo::isError: throw XrdSsiException(eInfo.Get());
// To implement detached requests, add another callback type which saves the handle
case XrdSsiRespInfo::isHandle: throw XrdSsiException("Detached requests are not implemented.");
// To implement file requests, add another callback type
case XrdSsiRespInfo::isFile: throw XrdSsiException("File requests are not implemented.");
// To implement stream requests, add another callback type
case XrdSsiRespInfo::isStream: throw XrdSsiException("Stream requests are not implemented.");
// Metadata-only responses and data responses
case XrdSsiRespInfo::isNone:
case XrdSsiRespInfo::isData:
......@@ -191,17 +197,14 @@ bool Request<RequestType, MetadataType, AlertType>::ProcessResponse(const XrdSsi
}
else
{
//ErrorCallback("metadata.ParseFromArray() failed");
Finished();
delete this;
break;
throw PbException("metadata.ParseFromArray() failed");
}
}
// If this is a metadata-only response, there is nothing more to do
if(rInfo.rType == XrdSsiRespInfo::isNone)
{
// If this is a metadata-only response, we are done
Finished();
delete this;
break;
......@@ -216,6 +219,24 @@ bool Request<RequestType, MetadataType, AlertType>::ProcessResponse(const XrdSsi
GetResponseData(response_bufptr, m_response_bufsize);
}
}
}
catch(std::exception &e)
{
// Pass the exception to the Alert callback to be logged
AlertType alert;
ExceptionHandler(e, alert);
AlertCallback(alert);
// Return control of the object to the calling thread and delete rInfo
Finished();
// It is now safe to delete the Request object (which implies that the pointer on the calling side
// will never refer to it again and the destructor of the base class doesn't access any class members).
delete this;
}
return true;
......@@ -231,22 +252,7 @@ XrdSsiRequest::PRD_Xeq Request<RequestType, MetadataType, AlertType>
if(response_buflen != 0)
{
#if 0
// How do we handle message boundaries for multi-block responses?
// Deserialize the response
ResponseType response;
if(response.ParseFromArray(response_bufptr, response_buflen))
{
ResponseCallback(response);
}
else
{
ErrorCallback("response.ParseFromArray() failed");
}
#endif
// Handle one block of response data
}
// If there is more data then get it, otherwise clean up
......@@ -287,15 +293,14 @@ void Request<RequestType, MetadataType, AlertType>::Alert(XrdSsiRespInfoMsg &ale
AlertType alert;
if(alert.ParseFromArray(alert_buffer, alert_len))
if(!alert.ParseFromArray(alert_buffer, alert_len))
{
AlertCallback(alert);
}
else
{
//ErrorCallback("alert.ParseFromArray() failed");
PbException e("alert.ParseFromArray() failed");
ExceptionHandler(e, alert);
}
AlertCallback(alert);
// Recycle the message to free memory
alert_msg.RecycleMsg();
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment