zephirworks blog

  • Cloud Foundry e Ruby on Rails - seconda parte

    • Pietro Giorgianni
    • 19 Sep 2011
    • 0 Responses
    •  views
    • Ruby on Rails cloud deploy paas
    • Edit
    • Delete
    • Tags
    • Autopost

    Nel post precedente ho parlato di Cloud Foundry di VMware, la prima Platform as a Service open, e di come testare la propria applicazione Ruby on Rails su Micro Cloud Foundry in una virtual machine sul proprio Mac (naturalmente è possibile usare Micro Cloud Foundry anche su GNU/Linux o MS Windows, cambia solo la versione di VMware da installare!).

    Avevo anche anticipato di aver incontrato qualche difficoltà; ecco che ne parlo.

    Configurazione di Rete

    All'avvio di Micro Cloud Foundry, come raccontavo, viene mostrato un breve menu che propone di configurare varie cose, fra cui la rete. Nel post precedente ho detto di aver scelto DHCP; quello che, per semplicità, ho taciuto, è che il DHCP non ha funzionato.

    Sniffando la rete, ho scoperto che il problema è legato al timeout del client DHCP, troppo breve. È una cosa che ho già visto succedere in altri server out of the box, che a quanto pare si aspettano di ricevere una risposta entro pochissimi istanti.

    Niente di grave, Alt-F2, entro con l'utente vcap, faccio le mie verifiche e infine faccio partire la rete. Nel frattempo, però, scopro dalla documentazione che è possibile usare Micro Cloud Foundry anche senza avere accesso alla rete.

    Utilizzare Micro Cloud Foundry offline

    Se non si dispone di un collegamento di rete, o se per qualunque motivo si vuole lavorare offline, è comunque possibile utilizzare Micro Cloud Foundry senza accedere alla rete, come descritto qui.

    Per farlo, bisogna innanzi tutto spegnere la macchina virtuale, configurare VMware per usare l'opzione NAT e riavviare Micro Clound Foundry, inserendo il token di configurazione:

    vcap.me

    Micro Cloud Foundry avvierà quindi la configurazione per l'utilizzo offline, impiegando un paio di minuti circa, dopo di che verrà mostrato l'ip della macchina virtuale.

    A questo punto è necessario creare un tunnel SSH tra la propria macchina e la macchina virtuale:

    ssh -L 80:IPDELLAMACCHINAVIRTUALE:80 vcap@IPDELLAMACCHINAVIRTUALE

    Fatto questo, è possibile procedere col deploy, avendo però l'accortezza di specificare api.vcap.me come target per vmc:

    vmc target http://api.vcap.me

    Deploy di applicazioni Ruby on Rails

    Per essere sicuri di poter usare la propria applicazione Rails con Micro Cloud Foundry, bisogna seguire alcuni accorgimenti.

    Usare Bundler

    In teoria, Micro Cloud Foundry supporta applicazioni 2.3 tradizionali, con le gemme specificate in config/environment.rb, purché freezate in vendor/gems.

    In pratica, ci sono molte probabilità che la vostra applicazione non funzioni.

    In questo e in altri casi, il messaggio d'errore fornito da vcap deploy è un po' criptico; è però possibile saperne di più col comando:

    vmc files NOMEAPPLICAZIONE logs/migration.log

    Il team di Cloud Foundry consiglia di usare sempre e comunque Bundler, e nel mio piccolo lo consiglio anch'io, e non solo per poter usare Cloud Foundry, ma soprattutto perché ci si guadagna in salute.

    Rubygems

    Un'altra questione che ho incontrato è legata alla versione di rubygems utilizzata: Micro Cloud Foundry usa attualmente rubygems 1.8.6, che ha problemi con il formato delle date nel gemspec di alcune gemme, tra cui paperclip e due dipendenze di Rails 3.1, ovvero rack-cache e tilt.

    Conviene quindi assicurarsi che le gemme utilizzate funzionino con rubygems 1.8.6 prima di effettuare il deploy su Micro Cloud Foundry.

    Conclusioni

    Questa prova con Micro Cloud Foundry mi ha mostrato che il prodotto è ancora giovane, ma molto promettente, e consente, con relativamente poca fatica, di testare le proprie applicazioni in un ambiente di pre-staging pulito e comodo.

    Micro Cloud Foundry promette di essere un'ottimo tool per vedere la propria applicazione in un ambiente di pre-staging, verificarne le performance, scoprire eventuali dipendenze impreviste, effettuare test d'integrazione e in genere capire come si comporterà l'applicazione in un ambiente di produzione, senza dover dedicare risorse e tempo prezioso per questo scopo.

  • Cloud Foundry e Ruby on Rails - prima parte

    • Pietro Giorgianni
    • 15 Sep 2011
    • 0 Responses
    •  views
    • Ruby on Rails cloud deploy paas
    • Edit
    • Delete
    • Tags
    • Autopost

    Da pochi mesi, VMware ha annunciato Cloud Foundry, la prima Platform as a Service open (Licenza Apache 2), che promette di rimuovere i costi e la complessità della configurazione dell'infrastruttura e degli ambienti di esecuzione, consentendo quindi all'utente di concentrarsi solo sullo sviluppo dell'applicazione, rendendo il deploy semplice e indolore.

    Cloud Foundry supporta Spring, Sinatra e Ruby on Rails, Node.js, Groovy, Grails, Scala e altre piattaforme.

    Volevo verificare di persona quanto sia semplice il deploy di un'applicazione Rails su questa piattaforma, sia per test da fare sulla propria macchina di sviluppo che in un ambiente di staging o di sviluppo, installando localmente Micro Cloud Foundry, una versione completa di Cloud Foundry che gira su una virtual machine, basata su Ubuntu Server a 64 bit.

    Ho deciso di raccontare questa prova in due post, uno con i passi di base da seguire quando tutto va bene, il prossimo con le difficoltà incontrate e le mie impressioni su questo software.

    Installazione

    Dal momento che la mia macchina di sviluppo è un macbook, per prima cosa ho installato VMware Fusion (versione di prova gratuita per 30 giorni); poi mi sono registrato sul sito di Cloud Foundry ed ho aspettato qualche ora prima di ricevere le credenziali d'accesso per poter scaricare Micro Cloud Foundry.

    Con quelle credenziali ho anche potuto generare un dominio di terzo livello per la mia applicazione di prova, sotto cloudfoundry.me. Fatto questo, mi è stato dato un token da inserire successivamente in Micro Cloud Foundry.

    Appena accesa la macchina virtuale, viene mostrato un menu molto scarno, e di fatto la scelta obbligata è la prima, "configure", che fa poche domande: password dell'utente vcap (che sta per VMware's Cloud Application Platform, ed è anche il nome del progetto su GitHub), configurazione di rete (DHCP o statica), token di configurazione del DNS.

    Deploy di un'applicazione

    Per il deploy di un'applicazione, si usa il tool a riga di comando vmc, da installare con:

    gem install vmc

    A questo punto, per prima cosa si deve indicare la destinazione del deployment, ovvero:

    vmc target http://api.TUODOMINIO.cloudfoundry.me

    Poi (solo la prima volta) occorre creare un utente, con:

    vmc register

    Verranno richiesti un indirizzo email e una password. Si può quindi procedere al login:

    vmc login

    Dopo aver digitato le credenziali immesse prima, si può finalmente eseguire il deploy vero e proprio; dalla directory dell'applicazione, digitare:

    vmc push

    Verranno richieste alcune informazioni, fra cui:

    • se usare il path corrente per il deploy;
    • nome dell'applicazione;
    • URL dell'applicazione (vedi più avanti);
    • se si tratta davvero di un'applicazione Rails come rilevato;
    • se si vogliono usare servizi, ovvero, attualmente, mongodb, mysql o redis.

    Pochi secondi dopo, il deploy è terminato e l'applicazione è accessibile su TUODOMINIO.cloudfoundry.me.

    Semplice, no?

    Beh, in realtà ho barato: confesso che ho incontrato qualche difficoltà, e che dopo diverse prove ho optato per il deploy di un'applicazione rails 3.0 hello world, o quasi, perché ci sono numerose limitazioni sul tipo di applicazione, le gemme e altro ancora. Nel frattempo però ho avuto modo di scoprire alcune cose interessanti su Micro Cloud Foundry, delle quali parlerò nella prossima puntata.

  • WIP

    • Andrea Campi
    • 1 Mar 2011
    • 0 Responses
    •  views
    • Ruby on Rails agile projects
    • Edit
    • Delete
    • Tags
    • Autopost

    Prefazione

    Venerdì scorso un'azienda amica ci ha contattato proponendoci un progetto piuttosto semplice: consumare alcuni feed, creati dinamicamente, aggiungere informazioni estratte da alcuni siti 2.0, e assemblare il tutto in un feed di output. Niente di complicato, tranne qualche piccolo dettaglio: volevano essere in produzione entro mercoledì. E naturalmente il tutto doveva essere molto, molto performante; ah, e scalabile.

    Normalmente tendiamo ad evitare progetti così piccoli e soprattutto con poco preavviso; però questo lavoro ci è sembrato interessante per diversi motivi. La sua stessa semplicità ci ha fatto pensare di evitare Ruby on Rails (la scelta è caduta su Sinatra), scelta stimolante che ci porta fuori dalla nostra "comfort zone". Allo stesso tempo sapevamo che non avremmo mai potuto garantire le prestazioni desiderate con tecniche "tradizionali", sequenziali: avremmo dovuto usare EventMachine e Fiber per aumentare il parallelismo, e Redis per distribuire il lavoro e gestire una cache aggressiva. In più la maggior parte di noi è stata molto impegnata nei mesi scorsi su progetti lunghi e complessi, per cui il pensiero di un progetto veloce e agile ci attraeva molto.

    Così dopo qualche scambio di email e telefonate per chiarire alcuni dettagli su specifiche, tempi e budget abbiamo deciso di partire lunedì mattina. Io e Pietro in peer programming, qualche metro quadrato di lavagna, e poco altro.

    Primo giorno, mattina

    Lunedì mattina, dopo le ultime verifiche col cliente si parte: creo il progetto in Redmine, repository git, Pietro alla guida iniziamo a scrivere qualche spec. Decidiamo di partire dal parsing dei feed (scelta più o meno obbligata), e ci troviamo già un po' spiazzati: la mancanza di Rails si sente un po', ci obbliga ad inventarci la struttura del progetto, comunque molto semplice. Poco male, decidiamo di impostare la struttura del progetto sulla falsariga di altri lavori, poi l'abitudine al TDD e la conoscenza già solida di Nokogiri ci fanno prendere un ritmo relativamente veloce.

    La parte più noiosa è creare qualche file di input, e il relativo output atteso (come asserzioni RSpec o direttamente sotto forma di file), visto che non ci sono stati forniti dal cliente; ma è una buona occasione di verifica col cliente: dimenticavo di dire, abbiamo a disposizione per due persone lato cliente, presenti su Skype--la cosa migliore dopo averle on site, un lusso raro!

    Ore 12, pausa caffé e sigaretta, il parser è finito e testato, non siamo in anticipo ma neanche in ritardo; è ora di pensare alla generazione del feed. Scegliamo Builder, lo conosciamo bene e sappiamo esattamente come vogliamo che sia fatto il nostro feed. Verifichiamo su Skype alcuni dubbi sul mapping, ora delle 13 è tutto committato e pushato.

    Nel frattempo i nostri colleghi hanno clonato una macchina virtuale di staging, per cui non vediamo l'ora di deployare. Ops, non abbiamo ancora collegato le nostri classi ad un server HTTP! Poche righe di Sinatra, facciamo qualche test nel browser e via: sappiamo già che dovremo rivedere questa parte quando introdurremo le Fiber, quindi non vale la pena scrivere test. Ed è a questo punto che abbiamo il primo imprevisto: la macchina di staging è rimasta vittima di un mix di Ruby 1.8 e 1.9, ci mettiamo un po' a fare pulizia e avere Passenger a posto (con Ruby 1.9.2). Aggiungiamo Capistrano al progetto, e siamo live.

    Intermezzo

    La scelta di seguire un approccio agile è stata presa insieme al cliente fin dal primo istante, soprattutto per via della timeline aggressiva. Avevamo anche concordato di deployare quasi subito una prima versione che era sostanzialmente un proxy inserito fra il loro frontend e il loro backend. Anche senza tutto il processamento e arricchimento che dovrà essere aggiunto nel corso del progetto, inserire la nostra applicazione nella catena appena possibile ci garantisce un'esposizione immediata ai dati e al feedback del cliente, con la possibilità di scoprire eventuali assunzioni errate più in fretta possibile.

    Questa secondo me è una scelta vincente che consiglio per qualsiasi progetto: anche una copertura di test del 100% non può salvare una consegna che non risponde alle esigenze del cliente!

    Pomeriggio

    Tocca a me guidare. Subito dopo pranzo abbiamo fatto il punto, sappiamo che entrando nel vivo avremo a che fare con un API che limita il numero di richieste per ora; la cosa ci preoccupa un po', temiamo che supereremo il limite. Per il momento non ce ne preoccupiamo troppo, ma verifichiamo col cliente come gestire questo e altri errori.

    Litighiamo una prima volta con Yajl: non l'abbiamo mai usato, non sappiamo bene quanto sia costoso chiamare istanziare un parser ogni volta per cui decidiamo di conservare un'istanza. E' un errore, ma nulla di grave. Alla fine comunque abbiamo un prototipo funzionante che ci permette di arricchire il feed con nuovi elementi, e abbiamo le relative spec.

    E immediatamente buttiamo via questo pezzo di codice e ripartiamo.

    Per chi non è abituato a sviluppare in modo agile potrà sembrare un'eresia, ma un prototipo "usa e getta" è comunque tempo ben speso: ora abbiamo le idee più chiare. Inoltre abbiamo dei test chiari e leggibili, e sappiamo che la seconda implementazione sarà completa quando i test saranno verdi.

    Abbiamo anche una conferma di quel che immaginavamo: l'API che dobbiamo chiamare è troppo lento per chiamarlo in modo sincrono; il nostro endpoint HTTP dovrà assumere che quasi tutto quel che gli serve sia già in cache su Redis, e lasciare che altri componenti si occupino di riempire la cache e tenerla aggiornata.

    A questo punto vorrei una gem già pronta che faccia l'equivalente delle fixtures Rails per popolare Redis prima di ogni test; troviamo redis-dump, che oltre ad avere dei tool a riga di comando ci da un API Ruby. Ma litighiamo di nuovo con Yajl, mi fisso di volerlo risolvere e buttiamo via una mezzora buona; sigh. Finalmente mi arrendo, do ragione a Pietro e scegliamo una strada più semplice, ovvero caricare i dati in Redis esplicitamente. La cosa non mi soddisfa, mi riprometto di tornare sull'argomento, ma non ora.

    Ormai sono quasi le 6, agganciamo le nuove classi a Sinatra e deployamo... e otteniamo una fantastica eccezione :(

    Per semplificare i test avevamo deciso di sostituire Time.now con uno stub che ritornava un DateTime; un refactoring del pomeriggio non aveva tenuto conto di questo, e questo è il risultato. Poco male, aggiungiamo dei test, rideployamo e chiediamo al cliente di fare un'altra verifica.

    E' il momento della prima change request: il nostro referente è altrettanto preoccupato quanto noi per il rate limit dell'API, e ci chiede di limitare ulteriormente le nostre richieste, lasciandone una parte libera. Accetto con riserve, principalmente perché è un aspetto che avevamo comunque considerato; penso che potremo gestirlo in modo simile. Ad ogni modo, apro un ticket per questa modifica, e vado finalmente a casa.

    Conclusioni

    Per quanto mi riguarda il risultato più evidente della giornata di oggi è la considerazione di quanto diamo per scontato quando lavoriamo in Rails, e non lo è affatto appena ce ne allontaniamo; dalle piccole cose come Object#try, a HashWithIndifferentAccess, ma soprattutto in termini di organizzazione del progetto. Sicuramente la nostra scarsa conoscenza di Sinatra (finora l'abbiamo usato solo per cose ancora più piccole) ci penalizza, e sicuramente esistono best practice che ignoriamo; d'altra parte di Sinatra abbiamo apprezzato la velocità.

    Ad ogni modo, la giornata di domani sarà ancora più interessante: Redis, EventMachine e Fiber tutte insieme!

  • Programmatori PHP, su la testa!

    • Andrea C. Granata
    • 22 Feb 2011
    • 0 Responses
    •  views
    • Humour PHP Ruby on Rails
    • Edit
    • Delete
    • Tags
    • Autopost

    Vi sentite sbeffeggiati continuamente dai vostri colleghi che usano Ruby (o Python)? Eccovi un post che spiega finalmente perché PHP è meglio.
    http://najafali.com/php-is-better-than-ruby.html

  • Unloadable monkey-patching for fun and profit

    • Andrea C. Granata
    • 20 Oct 2010
    • 0 Responses
    •  views
    • Ruby on Rails
    • Edit
    • Delete
    • Tags
    • Autopost
    Tonight I finally got around to looking at a tricky issue a colleague of mine has been battling for a bit, which gave me some interesting insight in how classes are unloaded in Ruby on Rails when in development mode. It's a rather advanced topic, and one which is not very clearly documented anywhere I could find, so there you go. First some background. One of our products, which we have been developing and selling in stealth mode for a while now, is approaching a major milestone, and my colleague Pietro has been prototyping an extension system to allow customers to write their own extensions. One of the requirements was that an extension could override a method from a Model; for example, adding new fields to be indexed in Solr. In theory, Sunspot makes it dead easy to set up your indexing in steps; you can just keep adding searchable blocks as you need them. Doing the same in an extension is a simple matter of reopening the Trinket class and adding asearchable block there. So you can do:

    This approach works fine, in theory. In practice, we had a combination of two factors that caused quite a bit of head-scratching in development mode, while seemingly working fine in production:

    • we added the extension directory to config.autoload_paths;
    • we also had some code in config.to_prepare, to determine the current theme and require a few files in advance.

    As you probably know, In development mode all your classes in the autoload paths get reload between each request, and the same happens in console when you enter reload!. Rails accomplishes this goal by unloading all classes, then calling config.to_prepare to give you the chance to set things up, and finally starting to load classes up again as they get used. So what was happening is that we were loading the extension class before the "real" class had a chance to load, and the work would then get overwritten. Once you realize what is really happening, the solution is pretty clear and it boils down to the simple golden rule of to_prepare: no monkey patching! To get more into details, this is what happens when you run reload! in the Rails console:

    1. reload! invokes fires all ActionDispatch::Callbacks callbacks;
    2. one of the callbacks is your to_prepare, so the given block gets executed;
    3. the set_clear_dependencies_hook initialized from Rails::Application::Bootstrap is another of those callbacks, and given the order rules for initializers, it is invoked later;
    4. in turn, it will call ActiveSupport::Dependencies.clear that will unload all classes;
    5. finally, models and other classes will be loaded again when required.

    The solution is a simple three steps:

    1. stop monkey-patching classes in config.to_prepare;
    2. in its place, perform any initial configuration in an initializer
    3. finally, if you want some code to be invoked after every reload!, wrap it inside a ActionDispatch::Callbacks.after, forcing your callback to be invoked after the unload.

    Admittedly, I'm not the biggest expert in this area, and I may have been vague on some parts; I still hope this post can be helpful and save someone a few hours of frustration.

  • About


    18046 Views
  • Archive

    • 2012 (4)
      • May (2)
      • March (2)
    • 2011 (36)
      • December (2)
      • November (2)
      • October (1)
      • September (5)
      • June (1)
      • May (5)
      • March (4)
      • February (12)
      • February (3)
      • January (1)
    • 2010 (1)
      • October (1)
    • 2008 (1)
      • December (1)

    Get Updates

    Follow this Space »
    You're following this Space (Edit)
    You're a contributor here (Edit)
    This is your Space (Edit)
    Follow by email »
    Get the latest updates in your email box automatically.
    Loading...
    Subscribe via RSS
    TwitterFacebookPageTumblr