What is the Twisted Framework ?!?

Every so often I am asked to describe certain frameworks like the Twisted Framework and this is my response for that one.

The Twisted Framework (Disclaimer: Some of the code in this document was written by Ray C Horn but the rest was not since it may be from some Open Source sources… nothing like stating the obvious…)

Advertisements

SleepyMongoose meets the Python after dark

 

For a while now I have been looking for a reasonable

REST-based NoSQL Database I can use from the Google App Engine just to avoid
having to pay Google for their database fees.

Earlier today… I was able to make the SleepyMongoose
snuggle-up with the Python for some after-hours fun in the dark.

SleepyMongoose

You can read-up about SleepyMongoose here.

It’s a REST-based interface for MongoDB that runs as a lightweight Python HTTP
Server – I will eventually get around to making this SleepyMongoose wake-up by
shoving some Stackless Python into it just for fun and because Stackless always
makes Python work better.

So what does the SleepyMongoose need once I get around to
using it from the Google App Engine ?

SleepyMongoose needs a slick Python wrapper so I don’t gotta
deal with all that REST stuff which after-all the REST interface is only needed
because Google doesn’t seem to care much about bandwidth consumption for
anything other than their own database and it just makes sense to make Google
give me a FREE No-Cost MongoDb Proxy which is what this is all leading to
anyway.

SleepyMongoose meets the Python

 So, since I am a pretty good Python coder I chose to whip-up

a Magic little object that allows me to get away from REST and right into
Python objects.

I implemented the SleepyMongoose API as documented in their Wiki.

Keep in mind the code presented here requires the Vyper
Logix Library as found here (shameless
plug, of course
).

Here’s a sample of what the usage looks like:

from vyperlogix import
mongodb

 

if (__name__ == ‘__main__’):

    import os,sys

   

    sm = mongodb.SleepyMongoose(‘127.0.0.1:27080’).db(‘gps_1M’).collection(‘num_connections’)

    results = sm.connect()

    print ‘sm.connect() #1
–> ‘
,results

 

    results = sm.server(‘mongodb://127.0.0.1:65535’).connect()

    print ‘sm.connect() #2
–> ‘
,results

 

    results = sm.server(‘mongodb://127.0.0.1:65535’).name(‘backup’).connect()

    print ‘sm.connect() #3
–> ‘
,results

 

    results = sm.docs({“x”:2}).insert()

    print ‘sm.insert() #1
–> ‘
,results

 

    results = sm.find({“x”:2})

    print ‘sm.find() #1 –>
,results

 

    results = sm.criteria({“x”:2}).remove()

    print ‘sm.remove() #1
–> ‘
,results

 

    results = sm.docs().insert({“x”:3})

    print ‘sm.insert() #1
–> ‘
,results

 

    results = sm.find({“x”:3})

    print ‘sm.find() #2 –>
,results

 

    results = sm.remove({“x”:3})

    print ‘sm.remove() #2
–> ‘
,results

 

    results = sm.docs([{“x”:2},{“x”:3}]).insert()

    print ‘sm.insert() #3
–> ‘
,results

 

    results = sm.criteria({“x”:2}).remove()

    print ‘sm.remove() #3
–> ‘
,results

 

    results = sm.criteria([{“x”:3}]).remove()

    print ‘sm.remove() #4
–> ‘
,results

 

    results = sm.insert([{“x”:2},{“x”:3}])

    print ‘sm.insert() #4
–> ‘
,results

 

    results = sm.remove({“x”:2})

    print ‘sm.remove() #5
–> ‘
,results

 

    results = sm.remove([{“x”:3}])

    print ‘sm.remove() #6
–> ‘
,results

    pass

Here’s the rest of the code:  (Simple and to the point, no nonsense code,
in a few hours…)

__copyright__ = “””\

(c). Copyright 2008-2011,
Vyper Logix Corp., All Rights Reserved.

 

Published under Creative
Commons License

(http://creativecommons.org/licenses/by-nc/3.0/)

restricted to
non-commercial educational use only.,

 

http://www.VyperLogix.com
for details

 

THE AUTHOR VYPER LOGIX
CORP DISCLAIMS ALL WARRANTIES WITH REGARD TO

THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND

FITNESS, IN NO EVENT SHALL
THE AUTHOR BE LIABLE FOR ANY SPECIAL,

INDIRECT OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING

FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT,

NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION

WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE !

 

USE AT YOUR OWN RISK.

“””

import logging

 

import urllib2

 

import simplejson

 

from vyperlogix import
misc

from vyperlogix.misc import _utils

from vyperlogix.classes import MagicObject

 

arg0 = lambda args:args[0] if (misc.isIterable(args)) and (len(args) > 0) and (misc.isString(args[0])) else None

list0 = lambda args:args[0] if (misc.isIterable(args)) and (len(args) > 0) and ( (misc.isList(args[0])) or (misc.isDict(args[0])) ) else []

int0 = lambda args:args[0] if (misc.isIterable(args)) and (len(args) > 0) and (misc.isInteger(args[0])) else None

bool0 = lambda args:args[0] if (misc.isIterable(args)) and (len(args) > 0) and (misc.isBooleanString(args[0])) else None

 

__only__ = lambda value,target:value if (str(value).lower().capitalize() == str(target).lower().capitalize()) else None

 

class SleepyMongoose(MagicObject.MagicObject2):

    def __init__(self,sleepy_mongoose):

        ”’

        See
also: https://github.com/kchodorow/sleepy.mongoose/wiki/

        ”’

        toks = sleepy_mongoose.split(‘:’)

        try:

            self.__sleepy_mongoose__ =
sleepy_mongoose if (misc.isString(toks[0]) and misc.isInteger(int(toks[-1]))) else None

        except:

            self.__sleepy_mongoose__ =
None

        self.__database__ = None

        self.__collection__ = None

        self.__server__ = None

        self.__server_name__ = None

        self.__last_exception__ =
None

        self.__n__ = None

        self.__docs__ = None

        self.__criteria__ = None

        self.__newobj__ = None

        self.__fields__ = None

        self.__sort__ = None

        self.__skip__ = None

        self.__limit__ = None

        self.__explain__ = None

        self.__batch_size__ = None

        self.__id__ = None

       

    def __http_get__(self,url):

        data = None

        try:

            response = urllib2.urlopen(url)

            json = response.read()

            data = simplejson.loads(json)

        except Exception, ex:

            self.__last_exception__ =
_utils.formattedException(details=ex)

            data = None

        return data

 

    def __http_post__(self,url,parms=()):

        from vyperlogix.url._urllib2 import
http_post

        data = None

        try:

            json = http_post(url,parms)

            data = simplejson.loads(json)

        except Exception, ex:

            self.__last_exception__ =
_utils.formattedException(details=ex)

            data = None

        return data

 

    def __handle_exceptions__(self):

        if (not self.__sleepy_mongoose__):

            logging.error(‘ERROR: Cannot understand “SleepyMongoose(%s)”‘
% (self.__sleepy_mongoose__))

        elif (not self.__database__):

            logging.error(‘ERROR: Cannot understand “db(%s)”‘ % (self.__database__))

        elif (not self.__collection__):

            logging.error(‘ERROR: Cannot understand “collection(%s)”‘
% (self.__collection__))

   

    def __getattr__(self,name):

        self.__n__ = name

        return super(SleepyMongoose, self).__getattr__(name)

 

    def __call__(self,*args,**kwargs):

        if (self.__n__ == ‘db’):

            self.__database__ = arg0(args)

            self.__reset_magic__()

        elif (self.__n__ == ‘collection’):

            self.__collection__ =
arg0(args)

            self.__reset_magic__()

        elif (self.__n__ == ‘server’):

            self.__server__ = arg0(args)

            self.__reset_magic__()

        elif (self.__n__ == ‘name’):

            self.__server_name__ =
arg0(args)

            self.__reset_magic__()

        elif (self.__n__ == ‘docs’):

            self.__docs__ = list0(args)

            self.__reset_magic__()

        elif (self.__n__ == ‘criteria’):

            self.__criteria__ = list0(args)

            self.__reset_magic__()

        elif (self.__n__ == ‘fields’):

            self.__fields__ = list0(args)

            self.__reset_magic__()

        elif (self.__n__ == ‘sort’):

            self.__sort__ = list0(args)

            self.__reset_magic__()

        elif (self.__n__ == ‘skip’):

            self.__skip__ = int0(args)

            self.__reset_magic__()

        elif (self.__n__ == ‘limit’):

            self.__limit__ = int0(args)

            self.__reset_magic__()

        elif (self.__n__ == ‘batch_size’):

            self.__batch_size__ =
int0(args)

            self.__reset_magic__()

        elif (self.__id__ == ‘id’):

            self.__id__ = int0(args)

            self.__reset_magic__()

        elif (self.__n__ == ‘explain’):

            self.__explain__ =
__only__(bool0(args),‘True’)

            self.__reset_magic__()

        elif (self.__n__ == ‘newobj’):

            self.__newobj__ = list0(args)

            self.__reset_magic__()

        elif (self.__n__ == ‘find’):

            if (self.__sleepy_mongoose__)
and (self.__database__) and (self.__collection__):

                p = []

                if (self.__criteria__):

                    p.append(tuple([“criteria”,simplejson.dumps(self.__criteria__)]))

                    self.__criteria__ = None

                if (self.__fields__):

                    p.append(tuple([“fields”,simplejson.dumps(self.__fields__)]))

                    self.__fields__ = None

                if (self.__sort__):

                    p.append(tuple([“sort”,simplejson.dumps(self.__sort__)]))

                    self.__sort__ = None

                if (self.__skip__):

                    p.append(tuple([“skip”,‘%d’%(self.__skip__)]))

                    self.__skip__ = None

                if (self.__limit__):

                    p.append(tuple([“limit”,‘%d’%(self.__limit__)]))

                    self.__limit__ = None

                if (self.__explain__):

                    p.append(tuple([“explain”,‘%s’%(self.__explain__)]))

                    self.__explain__ = None

                if (self.__batch_size__):

                    p.append(tuple([“batch_size”,‘%d’%(self.__batch_size__)]))

                    self.__batch_size__ = None

                if (self.__server_name__):

                    p.append(tuple([“name”,self.__server_name__]))

                url = http://%s/%s/%s/_%s’
% (self.__sleepy_mongoose__,self.__database__,self.__collection__,self.__n__)

                return self.__http_post__(url,tuple(p))

            else:

                self.__handle_exceptions__()

            self.__reset_magic__()

        elif (self.__n__ == ‘insert’):

            if (self.__sleepy_mongoose__)
and (self.__database__) and (self.__collection__):

                p = []

                if (self.__docs__):

                    p.append(tuple([“docs”,simplejson.dumps(self.__docs__)]))

                    self.__docs__ = None

                else:

                    p.append(tuple([“docs”,simplejson.dumps(list0(args))]))

                    self.__docs__ = None

                if (self.__server_name__):

                    p.append(tuple([“name”,self.__server_name__]))

                url = http://%s/%s/%s/_%s’
% (self.__sleepy_mongoose__,self.__database__,self.__collection__,self.__n__)

                return self.__http_post__(url,tuple(p))

            else:

                self.__handle_exceptions__()

            self.__reset_magic__()

        elif (self.__n__ == ‘update’):

            if (self.__sleepy_mongoose__)
and (self.__database__) and (self.__collection__):

                p = []

                if (self.__criteria__):

                    p.append(tuple([“criteria”,simplejson.dumps(self.__criteria__)]))

                    self.__criteria__ = None

                if (self.__newobj__):

                    p.append(tuple([“newobj”,simplejson.dumps(self.__newobj__)]))

                    self.__newobj__ = None

                if (self.__server_name__):

                    p.append(tuple([“name”,self.__server_name__]))

                url = http://%s/%s/%s/_%s’
% (self.__sleepy_mongoose__,self.__database__,self.__collection__,self.__n__)

                return self.__http_post__(url,tuple(p))

            else:

                self.__handle_exceptions__()

            self.__reset_magic__()

        elif (self.__n__ == ‘more’):

            if (self.__sleepy_mongoose__)
and (self.__database__) and (self.__collection__):

                p = []

                if (self.__id__):

                    p.append(tuple([“id”,‘%d’%(self.__id__)]))

                    self.__id__ = None

                if (self.__batch_size__):

                    p.append(tuple([“batch_size”,‘%d’%(self.__batch_size__)]))

                    self.__batch_size__ = None

                if (self.__server_name__):

                    p.append(tuple([“name”,self.__server_name__]))

                q = ‘?’+‘&’.join([‘=’.join(list(t)) for t in p]) if (len(p) > 0) else

                url = http://%s/%s/%s/_%s%s’
% (self.__sleepy_mongoose__,self.__database__,self.__collection__,self.__n__,q)

                return self.__http_get__(url)

            else:

                self.__handle_exceptions__()

            self.__reset_magic__()

        elif (self.__n__ == ‘cmd’):

            if (self.__sleepy_mongoose__)
and (self.__database__):

                p = []

                _c_ = list0(args)

                if (_c_):

                    p.append(tuple([“cmd”,simplejson.dumps(_c_)]))

                url = http://%s/%s/_%s’ % (self.__sleepy_mongoose__,self.__database__,self.__n__)

                return self.__http_post__(url,tuple(p))

            else:

                self.__handle_exceptions__()

            self.__reset_magic__()

        elif (self.__n__ == ‘remove’):

            if (self.__sleepy_mongoose__)
and (self.__database__) and (self.__collection__):

                p = []

                if (self.__criteria____):

                    p.append(tuple([“criteria”,simplejson.dumps(self.__criteria____)]))

                    self.__criteria____ = None

                else:

                    p.append(tuple([“criteria”,simplejson.dumps(list0(args))]))

                    self.__criteria____ = None

                if (self.__server_name__):

                    p.append(tuple([“name”,self.__server_name__]))

                url = http://%s/%s/%s/_%s’
% (self.__sleepy_mongoose__,self.__database__,self.__collection__,self.__n__)

                return self.__http_post__(url,tuple(p))

            else:

                self.__handle_exceptions__()

            self.__reset_magic__()

        elif (self.__n__ == ‘connect’):

            _token = self.__n__

            if (self.__sleepy_mongoose__):

                p = []

                if (self.__server__):

                    p.append(tuple([“server”,self.__server__]))

                if (self.__server_name__):

                    p.append(tuple([“name”,self.__server_name__]))

                url = http://%s/_%s’ % (self.__sleepy_mongoose__,_token)

                return self.__http_post__(url,tuple(p))

            else:

                self.__handle_exceptions__()

            self.__reset_magic__()

        else:

            logging.debug(‘DEBUG: Cannot understand “%s(%s,%s)”‘ % (self.n,args,kwargs))

        return self

 

 

Java is half the performance of Python and Ruby Fails to run this benchmark !

Benchmarks are about as valuable as… lies, damned lies and…

However given the limited value in doing benchmarks this particular use-case can highlight the relative weakness of Java while highlighting the relative strength of Python while highlighting the fact that even though Ruby was built for recursion it can FAIL completely or at-best give sloppy performance.

Be warned, if you love Java and/or Ruby you might not like this benchmark and the results presented here…

First the problem:

Factorial… plain and simple.

I wanted to see how well Stackless Python fares against standard Python where Stackless used recursion or something closer to recursion and regular Python 2.5.5.x used generators.  Bottom line is, generators smoke but you already knew this.

Then I wanted to see how well Ruby 1.8.7 versus Ruby 1.9.2 might fare since Ruby is known to be heavily optimized for recursion.  Bottom line is Ruby 1.8.7 falls dead-even with Stackless Python (DUH!) and well behind the Python Generator however Ruby 1.8.7 fares very well against Java and Java came in dead last across the board.  Ruby 1.9.2 fails completely for the most extreme use-case, as shown below.

The Results:

Factorial program using Stackless Python.
1000! / 998! = 999000
         8 function calls in 0.010 CPU seconds
10000! / 9998! = 99990000
         8 function calls in 0.234 CPU seconds

Factorial program using Python Generators.
1000! / 998! = 999000
         2004 function calls in 0.002 CPU seconds
10000! / 9998! = 99990000
         20004 function calls in 0.135 CPU seconds

Factorial program using Ruby 1.8.7.
1000! / 998!1000! / 998! = 999000
  0.016000   0.000000   0.016000 (  0.010002)
             user     system      total        real
10000! / 9998!10000! / 9998! = 99990000
  0.421000   0.062000   0.483000 (  0.555111)

Factorial program using Ruby 1.9.2.
1000! / 998!1000! / 998! = 999000
  0.000000   0.000000   0.000000 (  0.003000)
             user     system      total        real
10000! / 9998! FAILS due to Recursion Limit

Factorial program using Java.
1000!/998! = 999000
Runtime is :0.017

10000!/9998! = 99990000
Runtime is :0.389

Results Analysis: (From Fastest to Slowest, Top-down)

All runtimes are given in seconds unless otherwise indicated.
Factorial program using Ruby 1.9.2.
10000! / 9998!                                                          FAILS due to Recursion Limit

Factorial program using Python Generators.
1000! / 998! = 999000                                                    0.002 CPU seconds

Factorial program using Ruby 1.9.2.
1000! / 998! = 999000                   0.000000   0.000000   0.000000 (  0.003000)

Factorial program using Stackless Python.
1000! / 998! = 999000                                                    0.010 CPU seconds

Factorial program using Ruby 1.8.7.
1000! / 998!1000! / 998! = 999000         0.016000   0.000000   0.016000 (  0.010002)

Factorial program using Python Generators.
10000! / 9998! = 99990000                                                0.135 CPU seconds

Factorial program using Java.
1000!/998! = 999000                                                      0.017

Factorial program using Stackless Python.
10000! / 9998! = 99990000                                                0.234 CPU seconds

Factorial program using Java.
10000!/9998! = 99990000                                                    0.389

Factorial program using Ruby 1.8.7.
10000! / 9998!10000! / 9998! = 99990000   0.421000   0.062000   0.483000 (  0.555111)

Ruby 1.9.2 came in first or last, depending on how you look at such things, but only because it failed to run for the most extreme case.
Python 2.5.5.x Generators smoke, as expected !
Ruby 1.9.2 comes in just behind Python Generators. So much for Ruby 1.9.2 being the Python killer.
Stackless Python comes in just ahead-of or dead-even with Ruby 1.8.7 depending on how one takes the Ruby profiler results.
Java comes in ahead of Ruby 1.8.7 cross the board but only because one has to use BigDecimal to get Java to handle the large numbers. Python handles the transition from regular integers to large numbers as they are being processed - Java might fare better if this were the case for Java but sadly it is not.
Ruby 1.8.7 comes in dead last.
Download the code.

Final Thoughts

Obviously Ruby Generators would have fared better than recursion however given that Ruby recursion is supposed to smoke I felt it was only fair to test recursion in Ruby with Python Generators because Python Generators are supposed to smoke.  Test what is supposed to smoke against what is supposed to smoke.
Java sucks for any problem not covered by the typical design of the JVM however since Python has been tweaked over the years it tend to perform very well and more than adequately given it is dynamic where Java is more static at runtime.  If Python had been more heavily optimized it surely would have done much better however the goal here was to use off-the-shelf solutions rather than the hand-optimized kind.
Needless to say, Python could be made to run a whole lot faster than Java especially when the typical boundaries are being pushed well beyond the typical limits.  This is the ugly secret about Java but then look at how Java is being used in the real-world and you too will see where and how Java fails to please.

Python is the other white meat !

Java is the Enterprise favorite now but... Python is the language that gets the most lovin' when it comes to squeezing the most out of any programming problem.  I have personally pushed Python to the mat in terms of performance and it comes back asking for more.  I do not see anyone in the Enterprise doing anything like this with Java however I do see more multi-tier solutions with Java than would be required to make the systems work.

PogoPlug is FASTER than DropBox for my needs !!!

Been using PogoPlug for a while in parallel with DropBox with PogoPlug Agent running on one of my Mac Mini boxes (seems Apple is good for something after-all albeit a bit pricey as compared with the Atom alternatives since Mac Mini’s run pretty cheap).

PogoPlug is FASTER !!

Well FASTER than DropBox anyway…

FASTER than that damned silly NAS I wasted money on last year – it has something like 8 TB but is as slow as molasses even though it is connected to my LAN via 1 Gbps.  Go figure.

PogoPlug Agent is fast enough to be useful when it says I have 14 TB spread between the slow NAS and the Mac Mini that has 6 TB in the form of 3 TB USB 2.0 drives.  Damn Apple for not supporting USB 3.0 !   LOL   But at-least USB 2.0 is FASTER than SATA II NAS !!!  If you can believe that !!!  Or maybe the Mac Mini is just FASTER than whatever OS is running in the SATA II NAS ?!?   Who knows why it is FASTER… I just like FASTER.

PogoPlug Agent is FAST-enough to allow me to go searching for files from Windows 7 while at work with reasonably quick results even when no file indexing was done by me other than whatever PogoPlug is doing for me.

Is PogoPlug Secure ?

Who knows… all I know is if I didn’t build it then it is likely not secure enough for my tastes.

PogoPlug is likely not doing SSH when shipping files to and fro – seems too fast for any kind of encryption but for all I know they use SSL or nothing.

Back to learning more about the PogoPlug while I trust their software is not allowing every one on the planet into my files like DropBox has been known to do.

Needless to say, I am getting closer to ditching DropBox for my most important files… just getting some other things done before I get around to it while giving PogoPlug a spin for a while.

 

Ruby on Rails with Cherokee & Passenger for Ubuntu 11.04

Sometimes people get the feeling I just don’t like Ruby on Rails because the name “python” appears in my URL for this Blog… well I do like Ruby however since Ruby is such a performance HOG I have to temper my enthusiasm with a certain sense of reality by knowing how to do things Ruby really sucks at by using Python and other languages.  Every single thing that might cause Ruby on Rails to crash and die or simply fail to meet the performance criteria are the exact same things that NEVER cause problems for Python/Django.  You can say what you want about whatever you want but… Ruby is NOT the fastest gal on the dance floor although she has a ton of enthusiasm and wants to dance all night, Ruby just cannot dance as much or as fast as some of the other gals in the room.  Ruby will make you feel like she is a fun gal to be with but… at the end of the day, Ruby is just too much of a big fat performance HOG.  The Ruby Community needs to do a whole lot more work to make Ruby more nimble on the dance floor however to be fair Ruby has been getting more nimble due to the contributions of the Phusion folks who have given us Ruby Enterprise Edition and Passenger even though, and I recall this clearly because I was doing the Ruby thing when this was taking place in 2008, the Phusion folks held-back Passenger when it was new so they could get some cash for their efforts – so much for the Open Source Movement.  All things being equal, and they rarely are, I do like Ruby on Rails as much as any guy could enjoy dancing with a over-weight gal who has two left feet because after-all sometimes it is those over-weight gals who can be more fun at the party even though we guys all want fashion models it’s just not all that realistic to hold-out for your typical fashion model who would not give us mere mortal geeks the time of day let alone date us or whatever one does after the party these days.

The Challenge…

Recently someone told me there were “issues” while installing and using Ruby on Rails with Phusion Passenger for Ubuntu 11.04 however… as is generally the case with the work I do, I did not notice any problems but then I rarely notice “issues” since I take them in-stride and press-on to get the work done; actually I enjoy the little bumps along the way.

Step #1

Install Ubuntu 11.04 in Virtual Box or VmWare.

Make sure you choose to install “ssh” or you may have to issue the following command once the installation completes so you can use SSH to “talk” to your Ubuntu Appliance.

apt-get install openssh-server openssh-client

Step #2 – Install Cherokee Web Server

sudo apt-get update

sudo apt-get upgrade –V

sudo apt-get install python-software-properties

sudo add-apt-repository ppa:cherokee-webserver/ppa

sudo apt-get update

sudo apt-get install cherokee –V

You can test it using the following:

sudo cherokee-admin -bxxx.xxx.xxx.xxx -pxxxx -T32

nohup cherokee-admin -bxxx.xxx.xxx.xxx -pxxxx -T32 &

Step #3 – Install Ruby Enterprise Edition

wget http://rubyenterpriseedition.googlecode.com/files/ruby-enterprise_1.8.7-2011.03_i386_ubuntu10.04.deb

sudo dpkg -i ruby-enterprise_1.8.7-2011.03_i386_ubuntu10.04.deb

ruby -v

Step #4 – Install MySQL and Subversion

Okay this is where there was a minor bump but nowhere near what I would call an “issue”.

You will not encounter any bumps or issues if you follow this guide – the bumps and issues are all gone.

apt-get install build-essential curl bison openssl libreadline6 libreadline6-dev zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-0 libsqlite3-dev sqlite3 libxml2-dev libxslt-dev autoconf libmysqlclient-dev

What does all this do ?  Well it’s a bit of Ubuntu magic but it works.  I had to spend a bit of time doing some research however since I have been down this sort of path many times I was happy to learn something new and not only because someone told me this might be difficult and I just cannot resist doing something someone said was “difficult” because it never is, for me…

apt-get install mysql-server

apt-get install subversion

Step #5 – Check-out your Source code from SVN

Hey, this one is up to you but here’s a hint that will probably work for you.

Make a directory in your non-root user account, call this whatever you wish and put it where you wish.

Check to make sure the “bundler” gem is installed by using the following command:

gem list –local

If you don’t see that “bundler” gem you will have to issue the following command:

sudo gem install bundler

Then check-out your source code using:

svn checkout https://place-the-url-for-your-source-code-here folder-name-goes-here –username username-goes-here

Then issue the following commands:

cd folder-name-goes-here

bundler update

Right here is where you might have encountered some kind of “issue” with the mysql2 gem due to some kind of problem with building the native gem however that won’t happen if you used the directions found in this article. (If your Rails code doesn’t use MySQL then you are on your own, my source code does and it was fine…)

Step #6 – Start-up your Passenger Standalone Instances

cd folder-name-goes-here

passenger start

The cool thing about using Passenger Standalone is that it uses nginx and this means you can reverse-proxy your way to health and happiness by using Cherokee as the reverse-proxy.  Cherokee is a lightweight Web Server that is faster than Apache 2.x while using less RAM (it’s the uses less RAM thing that is more interesting since you will want to use your RAM to pack-in as many Passenger Standalone Instances as possible since Ruby on Rails is such a performance hog…).

Step #7 – Create some slick scripts for your Application Server

Write some slick scripts in the /etc/init.d directory to automate the start-up and shutdown of your Application Server.

Step #8 – Install Monit and Munin

See the details here. You will have to work-out the nitty-gritty details as to how to make this work for your specific needs.

Monit can be used to detect when your Rails Instances need to be killed and they will need to be killed whenever they run amok by allocating too much RAM or running away with too much CPU.

The one problem Monit may not be able to detect is whenever your Rails Instances cease to function as they sometimes might, from time to time.

Step #9 – Install Webmin, just for fun !

See the details here.  Once again, you will have to do some of the work to make this work for your needs.

Conclusion

At the end of the day, it just does not make any real sense to deploy your 20th Century Web Server any more because Cloud Computing is here and here to stay.

The Google App Engine makes Ruby on Rails make sense and not only because jRuby strikes my funny bone in just the right way, but then so does PHP for Java.

On the other hand… not everyone in Corporate America knows about or is willing to use the Google App Engine – they would rather use Amazon EC2 and pay for that resource than possibly get it for FREE from Google or maybe I am the only one who likes the challenge of getting it for FREE from Google rather than paying Amazon some real money.  Who is to say… I do enjoy the Challenge of seeing just how far I can take Google along for the ride before they mug me for money… LOL

 

PHP Adventures with Google App Engine (Part 3)

Sample Project for Google App Engine 1.5.0

You can download this sample project. Working Quercus with working pQd installed and ready to roll.

As always, some assembly may be required to fit your specific needs.  It’s pretty easy to get to this point for those who know where to find the information.

WordPress 3.1.3 for Google App Engine

At first blush, it seems to me, it should be pretty easy to do pretty much whatever anyone might want to do with WordPress simply by making some changes to one single PHP source file which in this case would be the wp-db.php file.  This one file handles SQL interactions for WordPress, generally for MySQL however any Db could be used including but not limited to some kind of REST interface in place of MySQL.

Why there are no ORM’s for PHP such that those who maintain the WordPress Source would not have wanted to use one is a mystery to me but then I would want to use an ORM just to make it easier to connect to a different Db just in case that might become an option.  A bit of research indicates there are some ORM’s for PHP however none of those made their way into the WordPress PHP source code.

Level of Effort for Maintenance of Google AppEngine Patch for WordPress

Assuming all the changes get made to the wp-db.php file and none are required in any other files… the level of effort to maintain this level of functionality for Quercus and the Google App Engine would be minimal and should pose no problems going forward.  My interest lies in creating an automated tool I could monetize such that anyone could upload and install the latest version of WordPress in the Google App Engine… well this speaks for itself.  I would personally love to see millions of people using the Google App Engine for this one purpose alone and if I could make a buck for each installation that would be gravy.  I am just amazed Google has not done this already.

This may become more than just a weekend project just to get WordPress 3.1.3 into the Google Cloud but it is at-least more than possible.

Enjoy.

Android Development Project #1 – Game Tube

Game Tube is a new Android App for Android 2.2+ and Adobe AIR 2.5+

Game Tube 1.0

Game Tube 1.0 will allow people to view certain selected Gaming Sessions for entertainment purposes only.

New Gaming Sessions will be added on a regular basis.

Game Tube 2.0

Game Tube 2.0 will allow users to “upload” their gaming videos via You Tube as a way to share their Brag Clips with other users of Game Tube 2.0.   People will have the option of installing a Desktop Version of Game Tube 2.0 to their Windows/Mac/Linux Desktop to Administer their Game Tube Brag Clips;  there may be some support in the Android version for this also.

Game Tube 3.0

Game Tube 3.0 will allow users to build their own Social Networks of friends and others they wish to share their videos with.  There may be a FaceBook App that interfaces with Game Tube 3.0 to allow users to share their Brag Clips via FaceBook.  Support for Twitter and other Social Networks may be added depending on user support and user requests.

Stay Tuned for the ride !

Check back here for additional details whenever they become available.

%d bloggers like this: