Q:

Web2py - Run Loop & Break Loop Without Locking Application

Not sure how to approach this type of problem (let alone do it efficiently). 
In my application, users should be able to click a button to initiate a process via ajax. They should also be able to stop that process at any time by clicking a stop button. Something like:
def start():
    session.test = True 
    items=["1","2","3","4"]
    while session.test == True:
        for item in items:
           ..do stuff..
        pass 

def stop():
    session.test = False

However, this does not work. Among the issues, when the loop is initiated the application locks. How can I have multiple users run their own loops (and be able to break out of them) without locking the application?
EDIT:
I should note that ..do stuff.. is leveraging a selenium browser. 

A:

When it comes to long-running tasks, it is a bad idea to execute that task in the web2py model, view, or controller, as this will block the entire request thread until the task completes. In the meantime, this also forces the server to open new threads for subsequent requests to that task. If you have too many active requests, your entire website will slow down or lock up. (There are solutions around this, like monkey-patching web2py with gevent, but that's an advanced topic)
In web2py, it is better to put a long running task in its own process (separate from the application process), and have the task communicate with the application via the db. Web2py has multiple solutions for this such as Cron, Homemade task queues, and the Scheduler. See here.
Let's do Homemade task queues because it is the easiest. In this example, We want to send out emails to confirm a book order. Currently we send out emails like this:
def controller():
     #... controller stuff (i.e. buyer purchased a book)
     #... send a confirmation email
     mail.send(
          to = 'buyer@example.com',
          subject = 'Bookstore order',
          message ='Thank you for your order! Your new book will ship within 24 hours.',
     )
     #... 5 seconds later (blocks)
     #... continue

However, this blocks the request for the entire time it takes to send the email (5 seconds, for example), because mail.send() is a slow-running task. This is not good for user experience, as the user will see his browser loading for 5 additional seconds.
Let's instead push the email to the db, and have a separate background process poll the db for new emails, and send it out. For example, in our controller:
def controller():
     #... controller stuff (i.e. buyer purchased a book)
     #... push confirmation email to db
     db.queue.insert(status='pending',
          email='buyer@example.com',
          subject = 'Bookstore order',
          message ='Thank you for your order! Your new book will ship within 24 hours.',
     )
     #... milliseconds later (no block)
     #... continue

Notice how it took milliseconds to complete this time, and the user will not see a slowdown on his browser.
In our web2py /private folder let's write our little background script in mail_queue.py:
## in file /bookstore/private/mail_queue.py
import time
while True:
    rows = db(db.queue.status=='pending').select()
    for row in rows:
        if mail.send(to=row.email,
            subject=row.subject,
            message=row.message):
            row.update_record(status='sent')
        else:
            row.update_record(status='failed')
        db.commit()
    time.sleep(60) # poll every minute for new emails

Notice how it behaves like a controller, as you get access to the same globals as a controller. The only difference is you must do db.commit() to save changes to the db.
Finally in shell, let's fire up the background process. Note, it will be in a separate process from the web2py application and will not interfere with each other.
python web2py.py -S app -M -R applications/bookstore/private/mail_queue.py

