monstar.rb update
April 24th, 2013
New update on the 
Now a -e –exec switch allows any system script/app to be launched via Process.spawn(SCRIPT)
PID processes are killed via
More on github monstar.rb repository.
New update on the 
Now a -e –exec switch allows any system script/app to be launched via Process.spawn(SCRIPT)
PID processes are killed via
More on github monstar.rb repository.
A new year, a new Codebits event by the incredible Sapo Team.
I will be attending the event once again in November’12,
now that the participation was accepted for the event.
The venue is amazing, see by yourself.
Its about code, programming, web, internet, networking.
How to programatically remove a Query parameter from an URI String in Ruby.
For the following URI:
http://example.com/resource?param1=1¶m2=2&offset=3
If one wants to remove the “offset” parameter, the following may help.
EDIT: if a left side only param exists, it will be removed. Something like param2 in:
http://example.com/resource?param1=1¶m2=&offset=3
On dumping and restoring PostgreSQL databases, there may be the case for restoring selected tables from a global db dump.
For this to happen one needs to have the right options when dumping the data.
pg_dump
$ pg_dump -Fc -U username database_name > db_dump
Now, we have a “restore customizable” compressed dump of the database.
From the postgres documentation:
-F format
–format=format
Selects the format of the output. format can be one of the following:
c
custom
Output a custom-format archive suitable for input into pg_restore.
Together with the directory output format, this is the most flexible
output format in that it allows manual selection and reordering of
archived items during restore. This format is also compressed by default.
pg_restore
To reorder database items, it is first necessary to dump the table of contents of the archive into a detailed file. This file will allow us to make a custom restore of the items (tables, etc) that we need.
$ pg_restore -l db_dump > db.list
Open the db.list file in your favorite editor (Vim) and proceed to comment or delete the lines of the item that you do not want to be restored.
From the postgres documentation there is a good example I changed here to comply with the previous dump:
;
; Archive created at Wed Dec 7 15:26:56 2011
; dbname: database_name
; TOC Entries: 306
; Compression: -1
; Dump Version: 1.12-0
; Format: CUSTOM
; Integer: 4 bytes
; Offset: 8 bytes
; Dumped from database version: 9.1.1
; Dumped by pg_dump version: 9.1.1
;
;
; Selected TOC Entries:
;
3; 2615 2200 SCHEMA - public pasha
1861; 0 0 COMMENT - SCHEMA public pasha
1862; 0 0 ACL - public pasha
317; 1247 17715 TYPE public composite pasha
319; 1247 25899 DOMAIN public domain0 pasha
…
One can carefully edit the file. Semicolons start a comment, and the numbers at the start of lines refer to the internal archive ID assigned to each item. Lines in the file can be commented out, deleted, and reordered. According to the example, one could edit this section of the file:
10; 145433 TABLE map_resolutions postgres
;2; 145344 TABLE species postgres
;4; 145359 TABLE nt_header postgres
6; 145402 TABLE species_records postgres
;8; 145416 TABLE ss_old postgres
This way, table species will no be restored, neither nt_header and ss_old.
If one try this, will see all the items like index information, relations, keys, etc.
After all set, one can restore the selected items from the dumped database:
$ pg_restore -L db.list db_dump
Needed to convert a client Microsoft SQLSERVER database to our PostgreSQL database server.
Lots of tables, severall Gigabytes of data.
FOR /F %A IN ('type tables.txt') DO bcp "dbo.%A" out "d:\export\path\%A.csv" -S SERVERNAME\SQLSERVEREXPRESS -d "databasename" -U SERVERNAME\username -C RAW -T -c -t "\t" -r "\n"
bcp command creates the CSV file.$ file -bi filename.csv$ recode ISO8859-1..UTF-8 *.csvfx_tip = "./../exported_data/some_table.csv"
h_tip = Hash.new
CSV.foreach(fx_tip, {:col_sep => "\t", :headers => false}) do |f|
h_tip.merge!(f[0] => f[1])
end
puts h_tip.to_yaml
FOR /F %A IN ('type tables.txt') DO sqlcmd -E -S SERVERNAME\SQLSERVEREXPRESS -d database -o %A -s ";" -W -Q "SELECT TOP 100 * FROM dbo.%A WHERE someting"
If your case is simpler and you need to make a straight port, you can export the SQL statements from SQL Server and then on Postgres something like:COPY tablename FROM '/tmp/table.data' WITH DELIMITER ',';
Used Tools:“Ritchie was best known as the creator of the C programming language and a key developer of the Unix operating system, and as co-author of the definitive book on C, The C Programming Language, commonly referred to as K&R (in reference to the authors Kernighan and Ritchie).”
Farewell Dennis Ritchie, your work changed my life.
C | Unix
Dear Steve, its not easy to “Stay Hungry. Stay Foolish”… damn, it isn’t. It’s not even fun most of the time. But when it is, it certainly rocks and pays up connecting all the dots left behind. Rest in peace.
jQuery.data( element,key,value )
“Store arbitrary data associated with the specified element. Returns the value that was set”
.data( key,value )
“Store arbitrary data associated with the matched elements.”
Performance difference: on this jsPerf test the last is about 84% slower.
So instead of:
$('#element').data('type', 'critical')
prefer:
jQuery.data('#element', 'type', 'critical')
(tested on Google Chrome 12.0.742 browser)
After re-reading Google Code - Page Speed - Optimize Caching section, I began implementing it on the Sinatra app part of our eClinic.Pro system. Later, after having it working, I found out that Sinatra has this amazing helper:
def last_modified(time)
return unless time
time = time_for time
response[’Last-Modified’] = time.httpdate
halt 304 if Time.httpdate(env[’HTTP_IF_MODIFIED_SINCE’]).to_i >= time.to_i
rescue ArgumentError
end
Commited the code with a farewell git commit -am “Awesome handmade conditional GET to leverage client caching”, pushed it and refactored it to use the instance method last_modified(timestamp), just to commit it again.
Combine this with a before filter, like:
before do
cache_control :public, :max_age => 31536000
db_version = Admin.first.created_at
last_modified db_version
end
In short, the client (browser) issues a request for some content via a URI to the server. The server receives the request and checks the Request Headers to see if a If-Modified-Since directive is defined. If not, a response['Last-Modified'] header is set to the current time and the execution flow will proceed to the Sinatra app request route to deliver a response [no client local caching scenario]. Yet, this timestamp will be used by the client (browser) cache manager to store it locally, together with the response payload, building a client-side local cache for this resource. Now, if there is another client request, to the same URI, this time a If-Modified-Since Request Header will be sent along the request. The server will catch it and compare to an expiry date, in this case, the
Acording to Google, using both Cache-Control: max-age and Last-Modified headers, or even Etag if necessary, instructs the browser to load previously downloaded resources from local disk rather than over the network. This is client (browser) caching.
Based on the documentation it is redundant to specify both Expires and Cache-Control: max-age, or to specify both Last-Modified and ETag. It makes note to use the Cache control: public directive to enable HTTPS caching for Firefox.
This allows the browser to efficiently update its cached resources by issuing conditional GET requests when the user explicitly reloads the page. Conditional GETs don’t return the full response unless the resource has changed at the server, and thus have lower latency than full GETs.
For this, I set the server to dispatch a 304 Not Modified response to the browser so that is gets the local cached content and presents it as the result of the request, with a:
Request Method: GET
Status Code: 304 Not Modified
This is quite important since I’m requesting
to be fetched, and the result of this is 13 miliseconds response time. Local content. The payload is considerable, about 136KB of JSON response for one of the areas. Adding up that for one of the pages I’m loading 3 payloads of these via jQuery, the main server Merb app is now feeling quite lighter due to this recent decoupling. This means lower CPU utilization, database access, bandwith and time to respond.
Combining this with application server caching, response times get quite improved.


Final Notes:
- Github SinatraRb documentation for (Object) last_modified(time);
- Google Code Optimize Caching page;
- HTTP Headers on Wikipedia;
- Google Chrome is an amazing browser to develop on, using the Developer Tools;
- still got to detect a “typo” on Google Code documentation.
For the sake of application decoupling on one of the Merb web apps we’re working on, we identified the separation of blocks that shouldn’t depend on each other, with the advantage of having fewer dependencies, and lower the risk of malfunction in one part of a system when the other part is changed.
So a Sinatra web app was built on another server/port, with a simple yet effective control panel for internal management and an API to generate JSON responses.
Some requests to that Sinatra app API are being made via jQuery originating on the Merb application. This represents a problem. Even if in the same server, but with a different port. The browser security model tells us that XMLHttpRequest, frames, etc. must have the same domain in order to communicate. Makes sense for security reasons, but at the same time distributed services feel the pain.
For production we use a server side proxy so that the request comes from the client to our (origin) domain and is dispatched to the Sinatra app on a port or server/port combination. But in development we use another technique to get around the same origin browser policy.
That’s where JSONP (JSON with Padding) makes its debut. jQuery > 1.5 brought some new features like the ability to control the callback configuration. If we specify an ajax call/request with dataType: "jsonp", jQuery adds a parameter to our request, with the standard name “callback”. That parameter name will be used as a function name to process data.
Callback function name can be overridden using the jsonp parameter, something like jsonp: 'onJSONLoad'. That will result in the callback parameter name change. So, we’d get http://new.server:port/service/parameter?onJSONLoad= followed by an unique stamp that jQuery creates for the request.
One of the advantages of controlling the callback parameter is related to better browser caching of GET requests, since it is set to false as default for ‘jsonp’ dataType ajax requests.
All the above in the client. What about the server ? Mind that the request is getting a new parameter. For the Sinatra app, we had to change the final response. So, based on the fact of the appearance of a callback parameter:
callback = params.delete('callback')
and in the end of the action:
final_response(callback, response)
with response being a well formed JSON object.
For the final_response method, we have:
def final_response( callback, res)
if callback
content_type :js
response = "#{callback}(#{res})"
else
content_type :json
response = res
end
response
end
This will make the necessary adjustment to the response for the case of cross domain requests or same (origin) domain requests.
So a simple jQuery function would be like:
$("#ep_search_medics").click(function() {
$.ajax({
type: 'get',
dataType: 'jsonp',
url: 'http://localhost:4567/dcipt/rosuvast',
success: function(data) { $("#ep_search_results_nr").html(data.count); },
error: function() { console.log("Error"); }
});
return false;
});
Final Notes:
- one can read more at the excellent jQuery page for ajax requests;
- be very confident on your JSON response. One can test for JSON validation in JSONLint;
- Google Chrome is an amazing browser to develop on, using the Developer Tools.
Source code: git repository at github
DataMapper has a defined method named first_or_create, very explicit name, that takes a condition and attributes as params. Its source code defined in dm-core-1.0.2/lib/dm-core/model.rb is:
def first_or_create(conditions = {}, attributes = {})
first(conditions) || create(conditions.merge(attributes))
end
What is does is simply find the first resource by conditions, or create a new resource with the attributes if none found. This always returns an instance of the resource found or created.
It became handy to create an update_or_create method, so I created:
module DataMapper
module Model
def update_or_create(conditions = {}, attributes = {}, merger = true)
(first(conditions) && first(conditions).update(attributes)) || create(merger ? (conditions.merge(attributes)) : attributes )
end
end # Module Model
end # Module DataMapper
There are differences to consider, like the merger param and the returned TrueClass bool upon update (and not an instance of the resource).
I found a merger param necessary because of the Serial type of properties. In the implementation of first_or_create method if we specify a Serial property as a search condition and the search has no success, then the conditions will be merged with the attributes and the Serial +1 will not be taken in account. Thus, in this implementation setting merger to false, search conditions will not be merged. Some examples:
Article.update_or_create({:id => 10}, {:name => "Spirou meet Franquin"})
If Article with ‘id’ 10 exists then it will receive a new name
If Article with ‘id’ 10 doesn’t exist, it will be created with {:id => 10, :name => “Spirou meet Franquin”}
Article.update_or_create({:id => 123}, {:name => "Fantasio meet Franquin}, false)
If Article with ‘id’ 123 doesn’t exist, it will be created with {:name => “Fantasio meet Franquin”} and a self sequential id:
EDIT: new implementation to always get a DataMapper Object:
Apple OSX Snow Leopard
System Version: Mac OS X 10.6.2
Kernel Version: Darwin 10.2.0
Install notes for PosgreSQL 8.4 install using the great
Homebrew by Adam Vandenberg.
Run the author’s installation script, and that’s it. Try:
$ brew help
$ brew search postgresql
$ brew install postgresql
/usr/local/Cellar/postgresql/8.4.2: 2297 files, 31M, built in 3.3 minutes
$ brew info postgresql
My advice ? Use Homebrew. True UNIX tool!
EDIT:
- sudo is no longer needed to install formulas system wide;
- the postgresql formula will be updated with recent postgres versions, so to check versions do: $ brew versions postgresql
Install notes for Datamapper do_postgres driver ruby gem on severall operating systems:
Apple OSX Snow Leopard
System Version: Mac OS X 10.6.2
Kernel Version: Darwin 10.2.0
(No Macports; No Homebrew)
PosgreSQL 8.4
I wanted to have PosgreSQL server working on the mac so that development is easier.
There is a .dmg package from the guys at EnterpriseDB that is a single click install. Check it at their downloads page. Get it. Install it. Everything goes into:
/Library/PostgreSQL/8.4
Now to install the do_postgres gem, I had to set the $PATH to:
$ export PATH=$PATH:/Library/PostgreSQL/8.4/bin
Now, installing the gem from rubygems.org should work:
$ gem install do_postgres
or
sudo env ARCHFLAGS='-arch i386' gem install do_postgres
Remember in OSX where your gems are installed, with or without root access using:
$ gem environment
Debian 5.0 Lenny
I have PosgreSQL 8.3 on my Debian servers, from the repositories. To install the do_postgres gem, you must get the header files for libpq5 (PostgreSQL library):
$ sudo apt-get install libpq_dev
$ sudo gem install do_postgres
Ubuntu 9.10 Karmic Koala
I have PosgreSQL 8.4 on my Ubuntu servers, from the repositories. To install the do_postgres gem, you must get the header files for libpq5 (PostgreSQL library):
$ sudo apt-get install libpq_dev
$ sudo gem install do_postgres
Date: Sat, 21 Nov 2009 22:15:15 -0500 (EST)
From: noreply@rubyforge.org
To: me@mydomain.com
Subject: [RubyForge] Gem index has been shut down
Hello -
You’re receiving this email because you’re a RubyForge project admin and a recent change robably affects you.
A few days ago we repointed gems.rubyforge.org to the gemcutter.org box. This means that Nick Quaranto’s excellent gemcutter app is now indexing and serving all the gems - so rather than having two gem indexes, we now have one. As a consequence of this, when you release files to RubyForge you will probably also want to do a “gem push” to get them onto gemcutter and into the main gem index.
Note that you can continue to release gems (and other files) at RubyForge; it’s just that gems won’t utomatically make it into the main gem index.
Yours,
The RubyForge support team
http://rubyforge.org/projects/support/
its next week, yet fun starts much sooner; conference; talks; code; lisbon; 3day => codebits
Just like last year a lot of hacks and experiments are expected.
Kudos to the SAPO team, the organisers, to build up such an impressive event.
Last saturday the local Linux group, PortoLinux had a meeting at the engineering faculty of Porto University to discuss about usage of diferent SCM’s.
Main systems covered, centralized vs distributed:
- Subversion
- Git
It was a good tech event, spent a good time there.
Some photos here.
“By: Mikio Hirabayashi - 2009-08-31 13:22
BTW, the project site of Tokyo products have been moved onto my own server.
http://1978th.net/
Though it has not been completed yet, I’ll write more English information about Tokyo products.”
So, to get the latest, head there.
Scripting definition files (sdefs) are XML files that describe everything
about an application scripting interface: terminology, implementation
information, and complete documentation. Applications may incorporate
them to define their own scriptability, and scripting clients such as
AppleScript and Scripting Bridge read them to determine what operations
an application supports.
man sdef
“Neo4j is a graph database. It is an embedded, disk-based, fully transactional Java persistence engine that stores data structured in graphs rather than in tables. A graph (mathematical lingo for a network) is a flexible data structure that allows a more agile and rapid style of development.”
From the site:
Neo4j is released under a GNU Affero General Public License, so read carefully. There’s a price table for commercial products that includes severall support levels.
Interesting article with links from Ilya Grigorik about Tokyo Cabinet, Tokyo Tyrant (remote network access to the DB, via a rest_client p.ex.) and the “magnifique” Lua programming language, integrated for the ease of creation of user _designed functions into the server. A question I asked is the ability, or lack, of dinamically feed the server with extensions, without the need for restarts (updates, etc).
Not to miss this article too: Tokyo Cabinet: Beyond Key-Value Store
Tokyo Cabinet starts here with a nice presentation from its creator, another Japanese developer Mikio Hirabayashi.
Ruby, Perl, Python et_al bindings available.
I tell you, “it’s Big in Japan”
I was contacted via Twitter for some support on getting vimblog.vim to work on MacVim, on Mac OSX Leopard. The unique problem is that it must be compiled with Ruby interpreter support. So here is a quick guide to do it, building from Macvim git repository:
# select a folder where to build the aplication on your area:
cd to_your_workingspace_apps_folder
# get (clone) MacVim from its MacVim.git repository:
$ git clone git://github.com/b4winckler/macvim.git
$ cd MacVim
$ cd src
# now let us configure it for macvim gui and for +Ruby (I’ll add +Python and +Perl) support:
$./configure --enable-gui=macvim --enable-rubyinterp --enable-perlinterp --enable-pythoninterp --with-ruby-command=/Users/pedro/.rvm/rubies/ruby-1.8.7-p357/
$ make
# Success ? Let’s build the MacVim.app
$ cd MacVim
$ xcodebuild
# Sucess ? Let’s try it…
$ open build/Release/MacVim.app
# now lets copy vimblog to $HOME
$ cp $HOME/Downloads/vimblog.vim $HOME/.vim/plugin
# insert your credentials
# now test the existence of the script. Run MacVim and execute
:B + TAB
# you shoud get code completion for the Blog command.
# get the 10 most recent articles
:Blog rp
if you get problems, before another build, do a:
$ make distclean
Screenshots:
macvim window
building space
Update
I wiped out the default OSX Ruby and use only RVM Rubies. So now to compile, one needs to specify the exact ruby interpreter. It’s updated on the ./configure statement above.
Update
One can use the default Ruby used by RVM, using the default rubies path like below:
$./configure --enable-gui=macvim --enable-rubyinterp --enable-perlinterp --enable-pythoninterp --with-ruby-command=/Users/pedro/.rvm/rubies/default/
Update
removed the old download place, and updated to the new one (above)
I subscrived to some mail publications from Sun Microsystems. After that, one gets the usual validation e-mail.
This one states:
“Dear Sun Community Member,
Thank you for subscribing to the following Sun Microsystems eNewsletter(s)/notifications:
[…]
Sun respects your email privacy and security. In order to start receiving these publications, you must first confirm your subscriptions. Please click on the url below to activate your subscription(s): https://subscriptions.sun.com/sunmailapi/Optin?id=999999999
Thank you for subscribing. We hope you find the information to be valuable.”
The problem here is that the confirmation URL query is nothing but a (*not* garbled) sequential ID. Altering the ID from the link, all the other subscrivers e-mail starts poping-up, and more, they get activated if not done yet.
So, the above “Sun respects your email privacy and security” isn’t quite as should be.
With a simple script, one can get all the Sun.com subscrivers. I can see a spammer doing a:
“Dear Sun.com subscriver, we are partnering with Sun.com to sell you this lovely vacuum cleaner.”
Dear Sun, prevent us from buying lovely vacuum cleaners, fixing these vulnerabilities.
TY.
Update: Less than 24h later, Sun contacted me and fixed (the e-mail adress obfuscation, yet one can still approve other confirmations randomly) it. Well done.
“Bespin proposes an open extensible web-based framework for code editing that aims to increase developer productivity, enable compelling user experiences, and promote the use of open standards.”
one can read this here.
Bespin’s initial prototype includes support for very basic features, but one can easily notice its power. Its all drawn in the canvas, every character, cursor blinks, scroll bars, text selection, etc. As a Vim user, I immediatly thought of Vim commands/keybindings in Bespin. Even the simpler and most generally used ones. Not even asking for .vim power scripting ability. And that is a feature any one of us* can write as soon as Bespin coders release a good API. And it is already in the air. Neat.
By the way, look.at.this.mockup.…
The collaborative coding feature isn’t active yet, but if one can give instant editing access to a file for a “check this class”, that’s going to probably replace lots of gists, pasties, etc, on a coder2coder basis.
Code repository access via Dashboard ? Yes please.
I have no doubts, this is going to be a very usable product, for this little I’ve seen. The look’n'feel seems great (even if I had no repeat-key
)
* floss
3 or 4 new projects ahead.
One of them will be CouchDB and Merb (no DataMapper, no ActiveRecord). The db schema is modeled by each user and upon criteria decisions.
All of them Git managed, as been doing for the last year.
Served by a Debian based Linux distro, coded under Debian, UNR (my lovely little netbook), and OSX, mainly in Ruby 1.8.7. Production server structure not defined yet but development phase will be Mongrel. May implement a very simple queuing system for a specific need.
Very likely use of AWS (not SimpleDB) for the sake of _simplicity_ .
Editor ? Vim.
None of this is of great interest for the project itself of course. I’ll be queuing 2 or 3 of them, in paralel with the main one. As in everything, time management is almost everything to GTD. Must. repeat. this. always.
… just marking this CouchDB Implementation technical post from Ricky Ho here to read tomorrow while hacking on my new Aspire One. Basically, Ricky’s posts are almost all a must_read.
Some things are pure smartness: Gist integrated with Vim by the use of vimscript for gist by Yasuhiro Matsumoto.
For reference:
:[from],[to] Gist -p # post lines (from, to) to gist privatelly
:[from],[to] Gist # post lines (from, to) to public gist
:Gist [xxxxx] # edit gist xxxxx
:Gist -l # lists my gists
:Gist -k # lits gists from all
I used Paul Dixon’s Paste bin when needed, specially by its simple interface and good highlighting features. Very good. But Gist makes me able to store my gists on my own account.
Quite nice.
During the three days of Codebits where our minds are focused on hacking code, learning, networking, coding, eating pizza, creating ideas and implementing them, I had the pleasure to meet and talk to Mitch Altman.
Mitch invents and hacks the coolest things.
Here at Make Magazine, you can see how his BrainMachine is built, and using it is quite an experience…
Yet, my favourite one is the Trippy RGB Waves (schematic, video, photos).
Like Mitch said, imagine a Trippy RGB full wall, how cool would it be walking by!
Paul Graham’s gluing the recession factor with lack of competition, investor semi-blindness, operating cheaply and time is [always] now. While evidence is a virtue, this is !new.
:note for non-programmers: ‘!’ as an alias for ‘not’
[update]
This slideshare leaked from, as stated, a Sequoia Capital presentation is worth to look at.
This is a small post to remember a great ruby programmer.
Ruby France announced Guy Decoux “disparition”:
“He was part of the generation of developers who switched from Perl to Ruby in the 90s. While his mastering of Perl was already great, his knowledge about Ruby was so deep and impressive that a lot of Rubyists would have been very happy to have the same one.”
Announcement at ruby-talk where we can see lots of appreciation and recognition for Guy’s work.
_why has a wonderfull post and drawing at Hackety.org.
The following paragraph from _why’s post:
“You’ll hear a lot of people say that we didn’t know who he was. That no one met him. But we all read alot of his code. And clearly that was how he wanted us to know him. Think of how that stands in such sharp contrast to the self-advertisement and vanity journalism of the Web today. We knew him, just not in the way we’re used to.”
Guy’s work in ruby-core libs lives inside the machines we daily operate.
Goodbye Guy Decoux.
Q: how in Routes/Markaby do we implement fragment identifiers # as in www.foo.bar/pedro#here, for named anchor jumps ?
H(int): is it necessary to parse the controller ?
H(int): can a regexp solve it ? ‘/foo/(\w+)#(\w+)’ doesn’t…
A: …
ActiveRecord database schema migration info is stored in the main database, so that if one needs to manually hack a migration (fastforward/rewind), just update TABLENAME_schema_infos column ‘version’ to a new value and manually change your schema. Next ‘boot’ may generate (or not) new migrations.
riverside=# select * from foobar_schema_infos;
id | version
—+———
1 | 1.4
(1 row)
In a self note, forget not to set option :id => false on join tables for has_and_belongs_to_many relations.
god.pt is well described here, @ karlus. We and some more fine guys will be focusing on Gathering of Developers in our city, Porto::Portugal::Europe. We’ll be doing presentations (mostly but not only technical ones), debating ideas, working together hopefully on projects, networking and building business (well, one of the first meetings was partially dedicated to push Nuno sysadminin’ skills to start a “pro” hosting company). Barcamp, First Tuesday, TechMeet, we’ll be having a bit of ‘em all.
The starting group talks Python (Nuno), Ruby (me and Mario), media and communication (Carlos), Php (and domain registering savoir-faire
Karlus), and guess what: we’re all on Twitter, like godevel is.
The developers part of GOD isn’t restricted to code_monkeys. We speak business, startup’ing, venture capital, economy, talks (long or lightning), beer, unix, languages, hw, sw, media, web, web, web, servers, life, laptops, frameworks, gossip, gadgets, working environments, projects, code, code, scripts, threads, scaling, architectures. We’ll be focusing less on ideas, more on work. Implementations. On doing it.
I look forward a code_day in wich we’ll be coding for ourselves/others under a strong networking environment, during wich lightning-talks will hopefully rise.
More to come soon…
As for now, I’m fighting threads and forks in Ruby…
I recently had to move from using FastCGI on Camping Ruby framework, to sweet Mongrel because of getting too much 500 HTTP errors under some load tests. Yes irc::zimbatm, me too.
When on FastCGI behing Lighttpd, upon each request, the code is loaded so after changing its source, it gets updated.
Now, under development, Mongrel(s), behind the same Lighttpd frontend, need to be restarted upon source code changes in the models, views, controllers or helpers (yet not CSS files, since they are taken care by lighty). Instead of moving to the xterm, kill the process and restart it i decided to automate it.
Since i was disconnected from the webz, I’ve done this script to detect file changes from a pre-specified array of files, monitored under a certain interval in seconds, with an action to start, kill, and restart an app (in my case, a Mongreled Camping web app).
Problem: Threads
Solution: Process::fork
The app load (in this case I load/execute ruby scripts) is done via Process::fork. A new process starts up each time this method is fired up upon a File.open(f, 'r').ctime change:
def load_app
@pid = Process.fork { load(@app) }
end
Before loading up a new updated instance of the app, the previous one must be terminated. Threads behaviour was problematic because of the thread tree termination in time. This is well done, in a safe mode, with Process::kill(signal, pid) and Process::wait(pid) that waits the pid process termination, essential in the case of Mongrel server.
def kill_app
Process.kill("KILL", @pid)
Process.wait(@pid)
end
As one can see
in this screenshot the main app process holds on while the child, in this case our Mongrel’ed Camping web app, is terminated and created a new one.
Verbose mode to assert its behaviour. Suits this specific need.
This is very usefull to make tests (Test::Unit:TestCase) run automatically upon source changes (will get to an Autotest clone).
Changing from load(@app) to system(@app), one can get any command be executed. ftp, cp, etc…
The script is here do download under a Ruby License.
Usage: monstar [options]
-a, --app SCRIPT.RB,PARAMS,...
-i, --interval VAL
-f, --files FILE,FILE1,...
-h, --help