Discover Your Perfect Stay

Coming Soon: Master Asynchronous Workflows in Ruby with EventMachine Deferrables

Understanding the Power of Deferrables

Modern software development often involves handling tasks that can run concurrently. EventMachine (EM), a well-known library in the Ruby community, provides powerful features for managing such tasks. Specifically, EM introduces two concurrency patterns to Ruby programmers: spawned processes and deferrables. In this article, we will delve into how to adopt deferrables for efficient and effective asynchronous workflows.

What are Deferrables?

EM's Deferrable module is heavily inspired by the 'deferred' concept in Python's Twisted framework. Essentially, Deferrables in Ruby allow you to execute blocks of code only when certain conditions are met, at a future point in time. This mechanism decouples the timing of an operation's initiation from its processing, facilitating a more flexible and responsive application design.

An Introductory Example

Consider the following Ruby code, which uses EM's Deferrable module:

 require 'eventmachine' class MyClass include EM::Deferrable def print_value(x) puts "MyClass instance received #{x}" end end EM.run { df = MyClass.new df.callback {|x| df.print_value(x) EM.stop } EM::Timer.new(2) { df.set_deferred_status :succeeded, 100 } } 

This code will wait for two seconds before printing "MyClass instance received 100" and exiting. While this might seem like a simplistic use-case, the same pattern is instrumental in handling more complex and asynchronous operations without blocking the main thread.

Practical Applications of Deferrables

Deferrables are incredibly useful in scenarios such as networking, where I/O operations do not need to block execution. For example, consider an HTTP server that needs to make requests to other services while still being responsive to new incoming connections. By employing deferrables, you can set up callbacks that get triggered upon the completion of these outbound requests, without halting the server's main event loop.

Manipulating Deferrable Execution

Deferrables allow you to attach any number of callbacks and errbacks that execute in response to success or failure status changes. This design pattern offers a separation of concerns, where the logic that initiates an operation is isolated from the logic that executes once the operation is complete or has failed. It not only enhances code clarity but also mitigates some common pitfalls associated with parallel programming such as race conditions.

Going Deeper with Callbacks and Errbacks

When you set the deferred status of an event using EM's Deferrable, all attached callbacks or errbacks are immediately executed in the order they were added. This promotes a predictable flow, which is often not the case with threaded applications. Moreover, if the deferred status is already determined, any new callbacks or errbacks added will run without delay.

Fine-Tuning Deferred Operations

If required, you can modify deferred status within callbacks or errbacks themselves, enabling dynamic control over subsequent operations. This facility for altering execution paths can be very powerful, accommodating complex scenarios where the data or the status obtained from an operation needs to be transformed before being used by another part of the program.

Extended Example with HTTP Request

Let's observe deferrables in action within the context of an HTTP request:

 require 'eventmachine' EM.run { df = EM::Protocols::HttpClient.request( :host=>"www.example.com", :request=>"/index.html" ) df.callback {|response| puts "Succeeded: #{response[:content]}" EM.stop } df.errback {|response| puts "ERROR: #{response[:status]}" EM.stop } } 

This code demonstrates how an immediate deferrable object is returned and is later updated with a success or failure, thus triggering the appropriate callback or errback. This pattern exemplifies asynchronous programming, where the request to 'www.example.com' is processed in the background, enabling your application to perform other tasks concurrently.

Conclusion and Further Resources

The Deferrable pattern, as implemented in Ruby's EventMachine, offers a robust mechanism for efficiently managing concurrency in your applications. By leveraging this pattern, software developers can write clean, maintainable, and non-blocking code that readily adapts to complex workflows across a variety of use cases. Interested readers should examine EM's unit tests and other auxiliary methods that offer syntactic conveniences around common Deferrable usage patterns.

Edinburgh

Aberdeen

Llandudno

Northampton

Brighton

Stockport

Torremolinos

Chelmsford

Manchester

Porto

Brentwood

Solihull

Cardiff

Bicester

Brecon

Skegness

Pickering

Evesham

San Francisco

Liverpool

Cambridge (Cambridgeshire)

London

Copenhagen

Dawlish

Arundel

Watford (Hertfordshire)

York

Stafford

Ilford

Swansea

Grassington

Ware

Paphos

Benidorm

Wimbledon

Eastbourne

Pontefract

Ascot (Berkshire)

Stranraer

Crewe

St Albans

Oldham

Port Isaac

Luton (Bedfordshire)

St Austell

Bath

Torquay

Birmingham

Pontypridd

Fareham

Glasgow

Margate

Aberaeron

Barmouth

Porthmadog

Lockerbie

Bournemouth

Nantwich

Wells

Sevenoaks

Twickenham

Grays

Herne Bay

Dover

Formby

Guisborough

Woolacombe

Newton Abbot

Cumbernauld

Falkirk

Seaton Carew

Wigan

Bristol

Dublin

Morecambe

Lincoln

High Wycombe

Ealing

Leamington Spa

Knutsford

Blyth (Northumberland)

Duxford

Buffalo

Fort Atkinson

Center

Dorchester

Combe Martin

Alfreton

Blackburn (Lancashire)

Camber

Worthing

Weymouth

Maidenhead

Brixham

Frome

Padstow

Cowes (Isle of Wight)

Beverley

Heywood

Sowerby Bridge

Exeter

Cannock

Bridlington

West Bromwich

Battle

Macclesfield

Corfe Castle

Milngavie

Orange

Malton

Hastings

Hendon

Witney

Borehamwood

Rochdale

Scunthorpe

Kilmarnock

Castle Combe

Tring

Christchurch (Dorset)

Muncie

Epsom

Lynton

Portrush

Runcorn

Smithfield

Lowestoft

Llandrindod Wells

Inverurie

Trowbridge

Ulverston

Uttoxeter

Westerham

Scarborough

Corby

Cheshunt

Upminster

Shrewsbury

Reigate

Richmond (North Yorkshire)

Settle

Bowness-on-Windermere

Hyde

Haverfordwest

Newport (Gwent)

Clapham (North Yorkshire)

Beaulieu

Towcester

Waddesdon

Paisley

Llanberis

Gillette

Abersoch

Ames

Easley

Smyrna

Porthcurno

Henderson

Little Falls

Lansing

Burlingame

Rialto

Price

Ellsworth

Madison

Vernon

Hebron

Castleton (Derbyshire)

Maumee

Madras

Lexington

Springfield

Roosevelt

Greenville

Buffalo

Caseville

Lymington

Celina

Lancaster

Bel Air

Marshall

Albany

Lombard

Buda

Pasadena

Atlantic

Eastham

Greenfield

Westfield

Gallatin

Southaven

Clayton

Colonial Beach

Laurel

Snoqualmie Pass

Needham

Newberry

La Mesa

Salina

Seaside

Simpsonville

Crested Butte

Richmond

Maryville

Mount Airy

Biggleswade

Cheboygan

Jerome

Louisville

Johnston

Delaware

Knoxville

Lee

Boonville

Elgin

Fort Mill

Hanover

Oregon

Turlock

Middletown

Plymouth

Brea

Gretna

Lenoir

Shakopee