otsdaq  v2_01_00
WorkLoopManager.cc
1 #include "otsdaq-core/WorkLoopManager/WorkLoopManager.h"
2 #include "otsdaq-core/MessageFacility/MessageFacility.h"
3 #include "otsdaq-core/Macros/CoutMacros.h"
4 #include "otsdaq-core/XmlUtilities/HttpXmlDocument.h"
5 #include "otsdaq-core/SOAPUtilities/SOAPCommand.h"
6 
7 #include <toolbox/task/WorkLoopFactory.h>
8 
9 #include <iostream>
10 #include <sstream>
11 #include <cstdlib>
12 #include <cassert>
13 
14 
15 using namespace ots;
16 
17 //========================================================================================================================
18 WorkLoopManager::WorkLoopManager(toolbox::task::ActionSignature* job) :
19  cWorkLoopType_("waiting"),
20  job_ (job),
21  requestNumber_(0),
22  requestName_ (job_->name())
23 {
24  __COUT__ << "Request name: " << requestName_ << " jobName: " << job_->name() << std::endl;
25 
26 }
27 
28 //========================================================================================================================
29 WorkLoopManager::~WorkLoopManager(void)
30 {}
31 
32 //========================================================================================================================
33 HttpXmlDocument WorkLoopManager::processRequest(cgicc::Cgicc& cgi)
34 {
35  return processRequest(composeWorkLoopName(requestNumber_++, cgi));
36 }
37 
38 //========================================================================================================================
39 HttpXmlDocument WorkLoopManager::processRequest(const xoap::MessageReference& message)
40 {
41  return processRequest(composeWorkLoopName(requestNumber_++, message),&message);
42 }
43 
44 //========================================================================================================================
45 HttpXmlDocument WorkLoopManager::processRequest(std::string workLoopName, const xoap::MessageReference* message)
46 {
47  HttpXmlDocument xmlDocument;
48  std::stringstream requestNumberStream;
49  RequestNumber requestNumber = getWorkLoopRequestNumber(workLoopName);
50  requestNumberStream << requestNumber;
51  std::stringstream reportStream;
52 
53  __COUT__ << "Processing request! WorkLoops: " << workLoops_.size() << " req: " << requestNumber << std::endl;
54  if(workLoops_.size() >= maxWorkLoops)
55  {
56  if(!removeTimedOutRequests())
57  {
58  reportStream << "Too many running requests (" << workLoops_.size() << "), try later!" << std::endl;
59  __COUT__ << "ERROR: " << reportStream.str() << std::endl;
60 
61  xmlDocument.addTextElementToData("RequestStatus", "ERROR");
62  xmlDocument.addTextElementToData("RequestName" , getWorkLoopRequest(workLoopName));
63  xmlDocument.addTextElementToData("RequestNumber", requestNumberStream.str());
64  xmlDocument.addTextElementToData("ErrorReport" , reportStream.str());
65  return xmlDocument;
66  }
67  }
68  time(&(workLoops_[requestNumber].requestStartTime));
69  workLoops_[requestNumber].requestLastTimeChecked = workLoops_[requestNumber].requestStartTime;
70  workLoops_[requestNumber].request = getWorkLoopRequest(workLoopName);
71  workLoops_[requestNumber].result = "EMPTY";
72  workLoops_[requestNumber].progress = 0;
73  workLoops_[requestNumber].done = false;
74  workLoops_[requestNumber].workLoopName = workLoopName;
75  if(message != 0)
76  workLoops_[requestNumber].message = *message;
77  try
78  {
79  workLoops_[requestNumber].workLoop = toolbox::task::getWorkLoopFactory()->getWorkLoop(workLoopName, cWorkLoopType_);
80  }
81  catch (xcept::Exception & e)
82  {
83  reportStream << "Can't create workloop, try again." << std::endl;
84  __COUT__ << "ERROR: " << reportStream.str() << std::endl;
85  xmlDocument.addTextElementToData("RequestStatus", "ERROR");
86  xmlDocument.addTextElementToData("RequestName" , getWorkLoopRequest(workLoopName));
87  xmlDocument.addTextElementToData("RequestNumber", requestNumberStream.str());
88  xmlDocument.addTextElementToData("ErrorReport" , reportStream.str());
89  removeWorkLoop(requestNumber);
90  return xmlDocument;
91  }
92 
93  try
94  {
95  workLoops_[requestNumber].workLoop->submit(job_);
96  }
97  catch (xcept::Exception & e)
98  {
99  reportStream << "Can't submit workloop job, try again." << std::endl;
100  __COUT__ << "ERROR: " << reportStream.str() << std::endl;
101  xmlDocument.addTextElementToData("RequestStatus", "ERROR");
102  xmlDocument.addTextElementToData("RequestName" , getWorkLoopRequest(workLoopName));
103  xmlDocument.addTextElementToData("RequestNumber", requestNumberStream.str());
104  xmlDocument.addTextElementToData("ErrorReport" , reportStream.str());
105  removeWorkLoop(requestNumber);
106  return xmlDocument;
107  }
108  try
109  {
110  workLoops_[requestNumber].workLoop->activate();
111  }
112  catch (xcept::Exception & e)
113  {
114  reportStream << "Can't activate workloop, try again." << std::endl;
115  __COUT__ << "ERROR: " << reportStream.str() << std::endl;
116  xmlDocument.addTextElementToData("RequestStatus", "ERROR");
117  xmlDocument.addTextElementToData("RequestName" , getWorkLoopRequest(workLoopName));
118  xmlDocument.addTextElementToData("RequestNumber", requestNumberStream.str());
119  xmlDocument.addTextElementToData("ErrorReport" , reportStream.str());
120  removeWorkLoop(requestNumber);
121  return xmlDocument;
122  }
123 
124  __COUT__ << "SUCCESS: Request is being processed!" << std::endl;
125 
126  xmlDocument.addTextElementToData("RequestStatus", "SUCCESS");
127  xmlDocument.addTextElementToData("RequestName" , getWorkLoopRequest(workLoopName));
128  xmlDocument.addTextElementToData("RequestNumber", requestNumberStream.str());
129 
130  return xmlDocument;
131 }
132 
133 //========================================================================================================================
134 bool WorkLoopManager::report(toolbox::task::WorkLoop* workLoop, std::string result, float progress, bool status)
135 {
136  RequestNumber requestNumber = getWorkLoopRequestNumber(workLoop);
137 
138  /*
139  __COUT__ << "Reporting result for request " << getWorkLoopRequest(workLoop) << " with req#: " << requestNumber << std::endl;
140  if(workLoops_.find(requestNumber) == workLoops_.end())
141  {
142  __COUT__ << "This MUST NEVER happen. You must find out what is wrong!" << std::endl;
143  assert(0);
144  }
145  */
146  workLoops_[requestNumber].result = result;
147  workLoops_[requestNumber].progress = progress;
148  workLoops_[requestNumber].done = status;
149  return true;
150 }
151 
152 //========================================================================================================================
153 xoap::MessageReference WorkLoopManager::getMessage(toolbox::task::WorkLoop* workLoop)
154 {
155  RequestNumber requestNumber = getWorkLoopRequestNumber(workLoop);
156  return workLoops_[requestNumber].message;
157 }
158 
159 //========================================================================================================================
160 bool WorkLoopManager::getRequestResult(cgicc::Cgicc &cgi, HttpXmlDocument &xmlDocument)
161 {
162  std::stringstream reportStream;
163  std::string requestNumberString = cgi.getElement("RequestNumber")->getValue();
164  RequestNumber requestNumber = strtoull(requestNumberString.c_str(), 0 , 10);
165 
166  __COUT__ << "Request: " << requestName_ << " RequestNumber=" << requestNumberString
167  << " assigned # " << requestNumber << std::endl;
168 
169  if(workLoops_.find(requestNumber) == workLoops_.end())
170  {
171  reportStream << "Can't find request " << requestNumber << " within the currently active " << workLoops_.size() << " requests!";
172  __COUT__ << "WARNING: " << reportStream.str() << std::endl;
173  xmlDocument.addTextElementToData("RequestStatus", "WARNING");
174  xmlDocument.addTextElementToData("RequestName" , "Unknown");
175  xmlDocument.addTextElementToData("RequestNumber", requestNumberString);
176  xmlDocument.addTextElementToData("ErrorReport" , reportStream.str());
177  return false;
178  }
179 
180  if(!workLoops_[requestNumber].done)
181  {
182  reportStream << "Still processing request " << requestNumber;
183  __COUT__ << "WARNING: " << reportStream.str() << std::endl;
184  //Resetting timer since there is a listener
185  time(&(workLoops_[requestNumber].requestLastTimeChecked));
186 
187  xmlDocument.addTextElementToData("RequestStatus" ,"MESSAGE");
188  xmlDocument.addTextElementToData("RequestName" , workLoops_[requestNumber].request);
189  xmlDocument.addTextElementToData("RequestNumber" , requestNumberString);
190  xmlDocument.addTextElementToData("ErrorReport" , reportStream.str());
191  std::stringstream progress;
192  progress << workLoops_[requestNumber].progress;
193  xmlDocument.addTextElementToData("RequestProgress", progress.str());
194  return false;
195  }
196 
197  //Request done and ready to be retrieved so I can remove it from the queue
198  xmlDocument.addTextElementToData("RequestStatus" , workLoops_[requestNumber].result);
199  xmlDocument.addTextElementToData("RequestName" , workLoops_[requestNumber].request);
200  xmlDocument.addTextElementToData("RequestNumber" , requestNumberString);
201  std::stringstream progress;
202  progress << workLoops_[requestNumber].progress;
203  xmlDocument.addTextElementToData("RequestProgress", progress.str());
204 
205  removeWorkLoop(requestNumber);
206  return true;
207 }
208 
209 //========================================================================================================================
210 bool WorkLoopManager::removeWorkLoop(toolbox::task::WorkLoop* workLoop)
211 {
212  return removeWorkLoop(getWorkLoopRequestNumber(workLoop));
213 }
214 
215 //========================================================================================================================
216 bool WorkLoopManager::removeWorkLoop(RequestNumber requestNumber)
217 {
218  if(workLoops_.find(requestNumber) == workLoops_.end())
219  {
220  __COUT__ << "WorkLoop " << requestNumber << " is not in the WorkLoops list!" << std::endl;
221  return false;
222  }
223 
224  if(workLoops_[requestNumber].workLoop == 0)
225  {
226  __COUT__ << "WorkLoop " << requestNumber << " was not created at all!" << std::endl;
227  workLoops_.erase(requestNumber);
228  return false;
229  }
230 
231  try
232  {
233  workLoops_[requestNumber].workLoop->cancel();
234  }
235  catch (xcept::Exception & e)
236  {
237  __COUT__ << "Can't cancel WorkLoop " << requestNumber << std::endl;
238  //diagService_->reportError("Failed to start Job Control monitoring. Exception: "+string(e.what()),DIAGWARN);
239  return false;
240  }
241  try
242  {
243  workLoops_[requestNumber].workLoop->remove(job_);
244  }
245  catch (xcept::Exception & e)
246  {
247  // ATTENTION!
248  // If the workloop job thread returns false, then the workloop job is automatically removed and it can't be removed again
249  // Leaving this try catch allows me to be general in the job threads so I can return true (repeat loop) or false ( loop only once)
250  // without crashing
251  // __COUT__ << "WARNING: Can't remove request WorkLoop: " << requestNumber << std::endl;
252  }
253  __COUT__ << "Deleting WorkLoop " << requestNumber << std::endl;
254  toolbox::task::getWorkLoopFactory()->removeWorkLoop(workLoops_[requestNumber].workLoopName, cWorkLoopType_);//delete workLoops_[requestNumber].workLoop; is done by the factory
255  workLoops_.erase(requestNumber);
256  return true;
257 }
258 
259 //========================================================================================================================
260 bool WorkLoopManager::removeProcessedRequests(void)
261 {
262  std::map<RequestNumber, WorkLoopStruct>::iterator it = workLoops_.begin();
263  while(it != workLoops_.end())
264  if(it->second.done)
265  removeWorkLoop((it++)->first);
266  else
267  ++it;
268  return true;
269 }
270 
271 //========================================================================================================================
272 bool WorkLoopManager::removeTimedOutRequests(void)
273 {
274  time_t now;
275  time(&now);
276  std::map<RequestNumber, WorkLoopStruct>::iterator it = workLoops_.begin();
277  __COUT__ << "Removing timed out " << std::endl;
278  for( ; it != workLoops_.end(); it++)
279  if(it->second.done && difftime(now,it->second.requestLastTimeChecked) > timeOutInSeconds)
280  {
281  __COUT__ << "Removing timed out request #" << it->first << " after " << difftime(now,it->second.requestLastTimeChecked) << " seconds." << std::endl;
282  removeWorkLoop(it->first);
283  return true;//since I return I don't care if the iterator pointer is screwed after I erase the element
284  }
285  __COUT__ << "Done Removing timed out " << std::endl;
286  return false;
287 }
288 
289 //WorkLoopName Format:
290 //RequestNumber-CommandToExecute<Argument1Name:Argument1Value,Argument2Name:Argument2Value...>
291 //Then the WorkLoop adds at the end /waiting
292 //========================================================================================================================
293 std::string WorkLoopManager::composeWorkLoopName(RequestNumber requestNumber, cgicc::Cgicc &cgi)
294 {
295  std::stringstream name;
296  name << requestNumber << "-" << cgi.getElement(requestName_)->getValue();
297  __COUT__ << "Request: " << requestName_
298  << " Value=" << cgi.getElement(requestName_)->getValue()
299  << " WLName: " << name.str()
300  << std::endl;
301  return name.str();
302 }
303 
304 //========================================================================================================================
305 std::string WorkLoopManager::composeWorkLoopName(RequestNumber requestNumber, const xoap::MessageReference& message)
306 {
307  SOAPCommand soapCommand(message);
308  std::stringstream name;
309  name << requestNumber << "-" << soapCommand.getCommand();
310  __COUT__ << "Request: " << requestName_
311  << " Value=" << soapCommand.getCommand()
312  << " WLName: " << name.str()
313  << std::endl;
314  if(soapCommand.hasParameters())
315  {
316  name << '<';
317  char separator = ',';
318  for(SOAPParameters::const_iterator it=soapCommand.getParameters().begin(); it!=soapCommand.getParameters().end(); it++)
319  {
320  if(it != soapCommand.getParameters().begin())
321  name << separator;
322  name << it->first << "|" << it->second;
323  }
324  name << '>';
325  }
326  return name.str();
327 }
328 
329 //========================================================================================================================
330 WorkLoopManager::RequestNumber WorkLoopManager::getWorkLoopRequestNumber(toolbox::task::WorkLoop* workLoop)
331 {
332  return getWorkLoopRequestNumber(workLoop->getName());
333 }
334 
335 //========================================================================================================================
336 WorkLoopManager::RequestNumber WorkLoopManager::getWorkLoopRequestNumber(std::string workLoopName)
337 {
338  workLoopName = workLoopName.substr(0,workLoopName.find('-'));
339  return strtoull(workLoopName.c_str(), 0 , 10);
340 }
341 
342 //========================================================================================================================
343 std::string WorkLoopManager::getWorkLoopRequest(toolbox::task::WorkLoop* workLoop)
344 {
345  return getWorkLoopRequest(workLoop->getName());
346 }
347 
348 //========================================================================================================================
349 std::string WorkLoopManager::getWorkLoopRequest(std::string workLoopName)
350 {
351  return workLoopName.substr(workLoopName.find('-')+1,workLoopName.find(std::string("/")+cWorkLoopType_)-workLoopName.find('-')-1);
352 }
353 
354 //========================================================================================================================
355 void WorkLoopManager::translateWorkLoopName(toolbox::task::WorkLoop* workLoop, SOAPCommand& soapCommand)
356 {
357  std::string request = getWorkLoopRequest(workLoop);
358  if(request.find('<') == std::string::npos)
359  {
360  __COUT__ << "Simple request" << std::endl;
361  soapCommand.setCommand(request);
362  }
363  else
364  {
365  size_t ltPosition = request.find('<');
366  size_t gtPosition = request.find('>');
367  size_t begin = ltPosition+1;
368  size_t orPosition;
369  size_t commaPosition;
370 
371  soapCommand.setCommand(request.substr(0,ltPosition));
372  while((commaPosition = request.find(',',begin)) != std::string::npos)
373  {
374  orPosition = request.find('|',begin);
375  soapCommand.setParameter(request.substr(begin,orPosition-begin),request.substr(orPosition+1,commaPosition-orPosition-1));
376  begin = commaPosition+1;
377  __COUT__ << "Comma: " << commaPosition << std::endl;
378  }
379  orPosition = request.find('|',begin);
380  soapCommand.setParameter(request.substr(begin,orPosition-begin),request.substr(orPosition+1,gtPosition-orPosition-1));
381  }
382  __COUT__ << soapCommand << std::endl;
383  //__COUT__ << name.substr(name.find(',')+1,name.find('/')-name.find(',')-1) << std::endl;
384 }
385