diff --git a/Web/Python/launcher.py b/Web/Python/launcher.py
index 9d3916d98bad26b055aa0ec53cb6530c59950af8..738b79da470fe9e007662936f085cdb0dcb81a58 100755
--- a/Web/Python/launcher.py
+++ b/Web/Python/launcher.py
@@ -13,6 +13,7 @@ from random import choice
 
 from twisted.internet import reactor, defer
 from twisted.internet.task import deferLater
+from twisted.internet.defer import CancelledError
 from twisted.python import log
 from twisted.web import server, resource, http
 from twisted.web.resource import Resource
@@ -282,11 +283,14 @@ class ProcessManager(object):
         for id in self.processes:
             self.processes[id].terminate()
 
-    def startProcess(self, session, ready_callback=None):
+    def _getLogFilePath(self, id):
+        return "%s%s%s.txt" % (self.log_dir, os.sep, id)
+
+    def startProcess(self, session):
         proc = None
 
         # Create output log file
-        logFilePath = self.log_dir + os.sep + str(session['id']) + ".txt"
+        logFilePath = self._getLogFilePath(session['id'])
         with open(logFilePath, "a+") as log_file:
             try:
                 proc = subprocess.Popen(session['cmd'], stdout=log_file, stderr=log_file)
@@ -316,6 +320,38 @@ class ProcessManager(object):
     def isRunning(self, id):
         return self.processes[id].poll() is None
 
+    # ========================================================================
+    # Look for ready line in process output. Return True if found, False
+    # otherwise. If no ready_line is configured and process is running return
+    # True.
+    # ========================================================================
+
+    def isReady(self, session):
+      id = session['id']
+
+      # The process has to be running to be ready!
+      if not self.isRunning(id):
+          return False
+
+      application = self.config['apps'][session['application']]
+      ready_line  = application.get('ready_line', None)
+
+      # If no ready_line is configured and the process is running then thats
+      # enough.
+      if not ready_line:
+          return True
+
+      ready = False
+
+      # Check the output for ready_line
+      logFilePath = self._getLogFilePath(session['id'])
+      with open(logFilePath, "r") as log_file:
+          for line in log_file.readlines():
+              if ready_line in line:
+                  ready = True
+                  break
+
+      return ready
 
 # ===========================================================================
 # Class to implement requests to POST, GET and DELETE methods
@@ -361,29 +397,81 @@ class LauncherResource(resource.Resource, object):
         if not session:
             return json.dumps({"error": "All the resources are currently taken"})
 
-        # Create response callback
-        d = deferLater(reactor, self.time_to_wait, lambda: request)
-        d.addCallback(self._delayedRender, session_id=session['id'])
-
         # Start process
-        proc = self.process_manager.startProcess(session, d)
+        proc = self.process_manager.startProcess(session)
 
         if not proc:
-            request.setResponseCode(http.OK)
+            request.setResponseCode(http.SERVICE_UNAVAILABLE)
             return json.dumps({"error": "The process did not properly start. %s" % str(session['cmd'])})
 
+        # local function to act as errback for Deferred objects.
+        def errback(error):
+            # Filter out CancelledError and propagate rest
+            if error.type != CancelledError:
+                return error
+
+        # Deferred object set to timeout request if process doesn't start in time
+        timeout_deferred = deferLater(reactor, self.time_to_wait, lambda: request)
+        timeout_deferred.addCallback(self._delayedRenderTimeout, session)
+        timeout_deferred.addErrback(errback)
+        # Make sure other deferred is canceled once one has been fired
+        request.notifyFinish().addCallback(lambda x: timeout_deferred.cancel())
+
+        # If a ready_line is configured create a Deferred object to wait for
+        # ready line to be produced
+        if 'ready_line' in self._config['apps'][session['application']]:
+          ready_deferred = self._waitForReady(session, request)
+          ready_deferred.addCallback(self._delayedRenderReady, session)
+          ready_deferred.addErrback(errback)
+          # Make sure other deferred is canceled once one has been fired
+          request.notifyFinish().addCallback(lambda x: ready_deferred.cancel())
+
         return NOT_DONE_YET
 
-    def _delayedRender(self, request, session_id=None):
-        session = self.session_manager.getSession(session_id)
-        running = self.process_manager.isRunning(session_id)
 
-        if session and running:
+    # ========================================================================
+    # Wait for session to be ready. Rather than blocking keep using callLater(...)
+    # to schedule self in reactor. Return a Deferred object whose callback will
+    # be triggered when the session is ready
+    # ========================================================================
+
+    def _waitForReady(self, session, request, d=None):
+        if not d:
+            d = defer.Deferred()
+
+        if not self.process_manager.isReady(session):
+            reactor.callLater(1, self._waitForReady, session, request, d)
+        else:
+            d.callback(request)
+
+        return d
+
+    # ========================================================================
+    # Called when the timeout out expires. Check if process is now ready
+    # and send response to client.
+    # ========================================================================
+
+    def _delayedRenderTimeout(self, request, session):
+        ready = self.process_manager.isReady(session)
+
+        if ready:
             request.write(json.dumps(filterResponse(session, self.field_filter)))
+            request.setResponseCode(http.OK)
         else:
-            request.write(json.dumps({"error":"Session did not properly started"}))
+            request.write(json.dumps({"error": "Session did not start before timeout expired. Check session logs."}))
+            request.setResponseCode(http.SERVICE_UNAVAILABLE)
+
+        request.finish()
 
+    # ========================================================================
+    # Called when the process is ready ( the ready line has been read from the
+    # process output).
+    # ========================================================================
+
+    def _delayedRenderReady(self, request, session):
+        request.write(json.dumps(filterResponse(session, self.field_filter)))
         request.setResponseCode(http.OK)
+
         request.finish()
 
     # =========================================================================