lateefj / Frisky (http://src.hackingthought.com/projects/frisky/)

Frisky is an Asynchronous WSGI web server. Cross-platform, high performance, caching and compression API's included, and lightweight. Test server running Frisky: http://src.hackingthought.com/

Clone this repository (size: 498.5 KB): HTTPS / SSH
$ hg clone http://bitbucket.org/lateefj/frisky/
commit 15: 8ebc1bf36ca1
parent 14: 12d5baa7906a
branch: default
Finally I believe we have support for running WSGI requests in a seperate process. Which should be the beginning of increase stability and performance. However so far performance appears to have decreased but I think that is because I need to tweak the caching system to support mulitple processes. Major milesotone, very exciting!
Lateef Jackson / lateefj
12 months ago

Changed (Δ946 bytes):

raw changeset »

TODO.txt (2 lines added, 1 lines removed)

frisky/httpd.py (3 lines added, 3 lines removed)

frisky/proc.py (10 lines added, 10 lines removed)

frisky/server.py (29 lines added, 2 lines removed)

samples/selector_sample/run.py (6 lines added, 4 lines removed)

Up to file-list TODO.txt:

1
1
Priorities:
2
 * Runs WSGI in seperate process for stability and performance
3
2
 * Create configuration file and support features listed below
4
3
5
4
@@ -56,6 +55,8 @@ grok - http://faassen.n--tree.net/blog/v
56
55
werkzeug - http://dev.timparkin.co.uk/2009/01/werkzeug-and-werkzeugish-example.html
57
56
repoze - http://blog.delaguardia.com.mx/index.php?op=ViewArticle&articleId=119&blogId=1
58
57
58
Static server blog - http://jtauber.com/blog/2009/01/26/serving_up_user_contributed_media_from_a_separate_server/
59
59
60
Caching:
60
61
Need to support cache invalidation programmatically and cache invalidation
61
62
timeouts

Up to file-list frisky/httpd.py:

@@ -352,8 +352,8 @@ class WSGIHandler(RequestHandler):
352
352
        # or can we pass the socket to write to ? Maybe can just pass
353
353
        # socket and it will work. Probably worth a try.
354
354
        if f is None:
355
            #f = proc.process_request_callback(self.callback, environ, response)
356
            f = self.callback(environ, response)
355
            f = proc.process_request_callback(server.CONFIG_FILE, environ, response)
356
            #f = self.callback(environ, response)
357
357
            
358
358
        # Write out the header
359
359
        self.wfile.write(str(response))
@@ -378,7 +378,7 @@ def start(host='0.0.0.0', port=7777, cal
378
378
    """
379
379
    # launch the server on the specified port
380
380
    s = Server(host, port, WSGIHandler, callback=callback)
381
    print "SimpleAsyncHTTPServer running on port %s" %port
381
    print "SimpleAsyncHTTPServer running on port %s" % port
382
382
    try:
383
383
        asyncore.loop(timeout=2)
384
384
    except KeyboardInterrupt:

Up to file-list frisky/proc.py:

@@ -5,9 +5,10 @@ try:
5
5
	#2.6+ processing compatability
6
6
	from multiprocessing import Pool, Queue
7
7
except:
8
	
8
	# 2.5 lowest support
9
9
	from processing import Pool, Queue
10
10
11
from frisky import server
11
12
log = logging.getLogger(name=__name__)
12
13
# TODO: THIS NEED TO BE CONFIGUREATION!!
13
14
REQUEST_TIMEOUT = 30
@@ -19,19 +20,18 @@ def create_pool():
19
20
	global pool
20
21
	pool = Pool(PROCESSES)
21
22
	
22
def handle_wsgi_request(callback, environ, response):
23
	return callback(environ, response)
23
def handle_wsgi_request(config_file, environ, response):
24
	if not server.CONFIGURED:
25
		server.load_config_file(config_file)
26
	#print('WSGI APPLICATION IS %s' % server.WSGI_APPLICATION)
27
	return server.WSGI_APPLICATION(environ, response)
24
28
25
29
26
def process_request_callback(callback, environ, response):
30
def process_request_callback(config_file, environ, response):
31
	
27
32
	if pool is None:
28
33
		create_pool()
29
		
30
	for x in inspect.getmembers(callback):
31
		print x
32
	
33
	print('module %s and function %s and dir %s' % (callback.__module__, callback.__call__, dir(callback)))
34
	result = pool.apply_async(handle_wsgi_request, (callback, environ, response))
34
	result = pool.apply_async(handle_wsgi_request, (config_file, environ, response))
35
35
	return result.get(timeout=REQUEST_TIMEOUT)
36
36
	
37
37

Up to file-list frisky/server.py:

@@ -14,7 +14,7 @@ def configure():
14
14
"""
15
15
16
16
"""
17
FAWPS CODE need to rigure out how to attribute correctly
17
FAWPS CODE TODO: figure out how to attribute correctly came from FAWPS code
18
18
"""
19
19
def redirect(start_response, location, permanent=None):
20
20
    header=[('location',location),
@@ -37,8 +37,13 @@ import logging
37
37
import logging.handlers
38
38
import mimetypes
39
39
40
import simplejson
41
40
42
from frisky.oracle import io
41
43
44
CONFIG_FILE = None
45
46
    
42
47
STATIC_CONFIG = {}
43
48
44
49
DOMAIN_ALIAS = []
@@ -48,6 +53,8 @@ LISTEN_PORT = 8080
48
53
LOG_FORMAT = '%(asctime)s %(levelname)-8s %(message)s'
49
54
LOG_DATEFORMAT = '%a, %d %b %Y %H:%M:%S'
50
55
56
WSGI_APPLICATION = None
57
51
58
DEFAULT_CONFIG = {
52
59
    'logging':{
53
60
        'level': logging.DEBUG,
@@ -59,7 +66,16 @@ DEFAULT_CONFIG = {
59
66
CONFIGURED = False
60
67
61
68
def configure(config):
69
    global CONFIGURED, WSGI_APPLICATION
62
70
    CONFIGURED = True
71
    if config.has_key('wsgi_callable'):
72
        callable = config['wsgi_callable']
73
        func = callable.split('.')[-1]
74
        im = '.'.join(callable.split('.')[:-1])
75
        # TODO: CLean this up so it isn't a rat nest.
76
        st = 'import %s\nglobal WSGI_APPLICATION\nWSGI_APPLICATION = %s.%s()' % (im, im, func)
77
        exec(st)
78
        
63
79
    if config.has_key('domain_aliases'):
64
80
        DOMAIN_ALIAS.extend(config['domain_aliases'])
65
81
    if config.has_key('url_forwards'):
@@ -175,7 +191,8 @@ def handle_callback(environ, start_respo
175
191
    if find_static_path(environ['PATH_INFO']):
176
192
        try:
177
193
            fpath = find_file_path(environ['PATH_INFO'])
178
            # Cache system
194
            logging.debug('fpath is %s' % fpath)
195
            # Default cache to false
179
196
            cache_file = False
180
197
            
181
198
            if STATIC_CONFIG.has_key('CACHE') and STATIC_CONFIG['CACHE']['static']:
@@ -200,6 +217,16 @@ def handle_callback(environ, start_respo
200
217
        except FileNotFoundException, fnfe:
201
218
           logging.warning("File not found for path %s" % environ['PATH_INFO'])
202
219
    return None
220
   
221
def load_config_file(config_file):
222
    print('Configuring with file %s' % config_file)
223
    f = open(config_file, 'r')
224
    config = simplejson.loads(f.read())
225
    configure(config)
203
226
    
227
if len(sys.argv) > 1:
228
    CONFIG_FILE = sys.argv[1]
229
    load_config_file(CONFIG_FILE)
230
204
231
205
232
    

Up to file-list samples/selector_sample/run.py:

@@ -7,7 +7,7 @@ Note: Yaro performance is horrible so no
7
7
8
8
import selector
9
9
10
from frisky import httpd
10
#from frisky import httpd
11
11
from frisky.oracle.io import optimize
12
12
13
13
# It seems to have a small performance impact 
@@ -23,11 +23,13 @@ def hello(environ, start_response):
23
23
    
24
24
    return ["Hello from Frisky Selector sample"]
25
25
    
26
    
27
if __name__ == '__main__':
26
def wsgi_callable():
28
27
    SELECTOR = selector.Selector()
29
28
    SELECTOR.add('/', GET=hello)
30
29
    SELECTOR.add('/hello/{name}', GET=hello_name)
30
    return SELECTOR
31
32
#if __name__ == '__main__':
31
33
    
32
    httpd.start(callback=SELECTOR)
34
    #httpd.start(callback=wsgi_callable())
33
35