When weird stuff happens... look at your config

I have recently added a cron job to ovosuite to start cleaning up expired trial sites as well as implementing the billing cycle. Under cocoon, its pretty simple to get this done because of the built in Quartz cron block.

<start-cocoon-stuff>

Basically all I did was setup the cron job in cocoon.xconf which points to an internal pipeline that fires off some flow script to handle the logic. To do this you add two entries in cocoon.xconf:

1: The trigger

<trigger name="daily-job" target="org.apache.cocoon.components.cron.CronJob/pipeline-daily"

concurrent-runs="false">
<minutes>1</minutes>
<hours>9</hours>
<days>*</days>
<months>*</months>
<weekdays>?</weekdays>
</trigger>

this defines a trigger (inside //component[@class="org.apache.cocoon.components.cron.CocoonQuartzJobScheduler"]/triggers) that will get the "org.apache.cocoon.components.cron.CronJob/pipeline-daily" and call it daily at 9:01am every day.

2: The Cron Job Component

<component role="org.apache.cocoon.components.cron.CronJob/pipeline-daily"
> logger="cron.pipeline">
<pipeline>ovo/cron/daily</pipeline>
</component>

This defines the component i want called from the above trigger...its the pipeline cron job that will call an internal pipeline defined in the <pipeline> tag.

</end-cocoon-stuff>

I had my flow script building up a basic log email which is sent to me, enabling me to check what the cron job did that day. I had it running over the weekend and when i came in on Monday, i found that i was getting each email twice. A quick look at my flowscript code showed it wasn’t a basic programming error.. and it wasn’t happening on my dev box... hmm was it some wierd threading/linux/scheduling issue?

I was able to reproduce the problem on the linux testing cluster... hmm starting to look like a linux issue...

Another symptom was my cocoon log files were getting truncated and messed up a bit..

I attached a debugger to the linux test cluster (boy i love being able to remote debug) and found that the quartz initialisation code was getting called twice, although the second time it was only breaking in the debugger randomly.... and very rarely at that... luckily i noticed on the second break's stack trace it was loading from the directory scanning as opposed to the server config: breakthrough! The other main difference between my local dev box and the linux servers is the way the deployment is configured. My local runs out of the /cocoon context path, while the linux boxes have the cocoon setup as the default context.

From there it only took a quick google to find i had setup the default context incorrectly by setting the docBase to point to the 'cocoon' directory.. The problem with this is that because the cocoon directory is in the webapps directory, it will get automatically deployed, making cocoon get deployed twice: once as the default app and again as /cocoon.

The final solution is to use the ROOT directory in the webapps folder (how did I miss that the first time round??) with a separate ROOT.xml file in conf/Catalina/<host>/ to setup my context. Now it works a charm :)
Posted on Monday, August 14, 2006 at 12:18PM by Registered CommenterOvosuite Team | Comments1 Comment | References5 References

MySQL + middlegen = Scaling Issue

Flashback to J2EE Dev times: During the development of an internal J2EE framework, I came across a scaling issue when using middlegen to generate my CMP beans when I hit a certain number of tables (60+ or so). From then on it started to become quite painful, as middlegen would appear to hang for minutes while it analysed the table structures. Looking at the mySQL log, it appeared the driver was requesting the create table syntax of every table in my database multiple times.

 

First I looked into the source of middlegen, to see if it was doing something wacky… It was using the DatabaseMetaData.getImportedKeys() method to determine what foreign keys refer to the table currently getting analysed. This seemed reasonable to me so I decided to look into the mysql driver’s implementation of this function to see what was going on. Turns out, the way the driver figures this out is by getting the create statement of every table in the db, checking to see if it contains a foreign key reference to the table getting tested. Because middlegen was doing this for every table, it would mean that for each table in the db, a “show create table” call was executed for every other table in the db (n * n)…. No wonder this didn’t scale all to well…

 

To get around this problem I hacked to driver apart to forcibly cache the results from the ‘show create’ statement, so next time DatabaseMetaData.getImportedKeys() was called, it would use locally cached information.. not the most elegant solution but it worked.

 

Unfortunately I don’t have the code anymore (which I cant believe.. very embarrassing… I believe I always thought I would clean it up before putting it under source control... well it was over a year ago…), but I still have a jar file of the hacked driver which I use when generating the middlegen beans. Needless to say, this is not production quality, hell, for all I know, the a more elegant solution has been rolled into the driver codebase… either way, I thought I would make the jar available here just in case…

 

Now back to today, quick update on what’s been happening: I’ve worked on buttonator.com for a couple of days adding accounts, and multilingual support (Chinese, Japanese and Arabic for now). Also added the concept of a hotlink template… During this I had to use the caching of ruby: gotta say its pretty darn cool. After coming from cocoon, it’s nice to be able to use something so easy and logical. We should be rolling of v2 beta of buttonator.com sometime this week.

Posted on Monday, July 24, 2006 at 05:09PM by Registered CommenterOvosuite Team | CommentsPost a Comment | References9 References

Deploying Ruby

I’ve recently moved over to the world of ruby on rails to develop portlets for Ovosuite. Coming from a J2EE background, I can say it’s a breath of fresh air: everything 'feels' light and nimble again... no massive build times, no waiting for containers to deploy, no CMP weirdness.... (Although active record can still give you a turn).

Admittedly my experience with ruby is very minimal, so when it came time to get the services running on our production environment, things became a little painful. Its the usual ruby set-up: apache2 + fast-cgi running on Linux (debian).

A couple of things I've learnt from the experience:

1:DO NOT USE p STATEMENTS!

The application I was deploying has debug 'p' statements (if your unaware, the p statement will print to stdout) littered through the code. This was causing a weird error: "malformed header from script. Bad header= XXX" to appear in my apache logs. It took me a little longer than usual to fix this one because I haven’t used cgi before (my web based skills went from ASP to PHP then onto J2EE). CGI takes the output (stdout) of the application and treats that as the HTTP payload for the web page. During development, rails runs using its internal HTTP server where 'p' statements appear on the console (convenient for debugging), but in a production environment (fast-cgi), those same p statements will be embedded in the server response, which apache cant handle.

The lesson from this is to use the rails logging facilities :) (Although what a really want for Xmas is a full debug environment with stepping and variable inspection etc.. I suppose I’ve been spoilt by java in that regard)

2:Watch what you keep in your session.

Rails has a nifty way of storing sessions (completely serialised to disk (or other)) to allow massive scalability potential. Unfortunately, after a restart, it looses track of what libraries are in use, so it may not be able to de-serialize the session again if you have something a bit exotic in there. This was the case for my the TZInfo: a cool time zone library we use. Apparently it uses a bunch of internal classes in the background to handle each time zone, so even if you have require_gem 'tzinfo' and include TZInfo in your code, it still cannot find your classes when loading the session. The easy way around this is to write a wrapper function that gets the time zone based on the string identifier stored in the session.

3.Basic Linux stuff.

OK, I'm the coder, not the Linux guy in the company, so there are a few other 'obvious' things:

Make sure execute permissions are on dispatch.fcgi

Make sure the shebang in dispatch.fcgi is pointing to /usr/local/bin/ruby

Make sure www-data can write to tmp, log and read everything else

Make sure you change the re-write run in public/.htaccess to use fast cgi instead of cgi:

RewriteRule ^(.*)$ dispatch.cgi [QSA,L] should be RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]

That’s about it for now...

Posted on Wednesday, July 12, 2006 at 10:43AM by Registered CommenterOvosuite Team | Comments5 Comments | References31 References

Welcome to the Dev part of the OVO Blog.

 

First up I’ll give a bit of a background into what is used to put the ovosuite together... then over time I'll be posting tidbits about the gotchas that got me, and how I overcame them.

A bit about myself first: I’ve been programming for around 10 years, started with c/c++ under windows, moved to cross platform (basically stopped using MFC and went back to ANSI C) for server side dev. In the same project the client was written using a mix of VB and MFC based activeX controls.. i did both.. This gave me a taste of DHTML because it used the DHTML control (shudder) to manage WYSIWYG template editing. I then moved on to building enterprise web applications using J2EE. We evolved an in-house framework to do this based on cocoon/mysql and jboss. We are now leveraging this experience to build ovo-suite using some tried and tested tech, mixed in with the latest web framework: ruby on rails.

Ovosuite is built using cocoon to manage the portaling functionality, while most of the portlet applications will/are be written using ruby. We decided on using cocoon for two reasons:

1. Existing experience- the previous FW we developed used cocoon on the front end: it's perfect for shunting data around the place (pretty much what a portal is)

2. Webdav support: The foundation of the ovo suite involves a DMS system. To get best OS integration (web folders), we wanted to use webdav. I couldn’t find any open source offerings written in ruby, so we decided to use Slide, a Webdav server written in Java. Cocoon and slide already co-exist quite nicely.

Now I thought I would start on a bit of a positive rant: Slide 2.1.

What can I say? They did it right (almost). We initially developed a once of solution using slide 1.0 many moons ago.. WHAT A PAINFUL EXPERIANCE!

I approached slide 2.x with a bit of trepidation.. after reading the feature set on the slide website, I was quite amazed/confidant.... until one of the other developers in the team (the one who had to do most of the slide 1.0 work) mentioned that slide had previously promised many of these features, but fell far short.

Well thank god for open source: all it took was a download of the latest branch, a quick squiz at the code and I knew we were set. Everything I needed for ovosuite is there: custom authentication, custom authorisation and events for auditing and quota management. And as an added bonus, integration with lucene, at no extra cost :) These are all the features we really missed having the first time around.

Well that’s enough for now.. I'll be posting more down the track... some rants, some raves.. and I'll try and avoid political stuff :)

Posted on Monday, July 3, 2006 at 03:40PM by Registered CommenterOvosuite Team | Comments1 Comment | References2 References

Welcome to the Ovosuite Blog

Welcome to our new development Blog!

Here our developers will be talking about devlopment issues, involving ajax, cocoon, ruby on rails, and the odd funny development story.

We will also have our marketing genius add his two bob's worth every now and then!

Please feel free to add your comments, ask questions and have a good time.

Our team will respond to any questions within 48 hours.

Cheers

Ovosuite development team

Posted on Thursday, June 29, 2006 at 10:50AM by Registered CommenterOvosuite Team | Comments1 Comment | References7 References