• Stars
    star
    114
  • Rank 308,031 (Top 7 %)
  • Language
    Clojure
  • Created about 12 years ago
  • Updated over 9 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Durable Atoms in Clojure

enduro

enduro provides a reference type similar to Clojure's native atom, except that enduro's is durable - its contents can be persisted as Clojure data to some durable backing store.

Currently, enduro atoms can be backed by:

  • files with file-atom: for memory-constrained applications where a database is not feasible, but where disk is available
  • PostgreSQL with postgresql-atom: for small-data web applications, like those you may deploy to Heroku. For an example of a simple Heroku hit counter project using enduro, see hitcounter.
  • memory with mem-atom: for local development and testing

A file-backed enduro atom works great on the Raspberry Pi!

Build Status

Usage

Dependency

Clojars Project

Example: File-backed

;; Require or use alandipert.enduro in your namespace. The primary functions it
;; provides are atom, swap!, reset!, and release!.

(ns your-ns
  (:require [alandipert.enduro :as e])

;; Call e/file-atom with a value and a path to a file to create a
;; file-backed atom. If the file is empty or doesn't exist, it will be
;; initialized with value. If the file isn't empty, your initial value
;; will be ignored and the file will be read.

;; :pending-dir should be specified if the data file resides on a file
;; system other than the current one.  This ensures atomicity of the
;; underlying file move.

(def addresses (e/file-atom {} "/tmp/addresses.clj" :pending-dir "/tmp"))

;; You can add watches to enduro atoms like any other reference type.

(add-watch addresses
           :new
           (fn [_ _ _ v]
             (println "new address" v)))

;; The swap! operation is synchronous, and returns only after the new value has
;; been committed to disk.

(e/swap! addresses assoc "Spongebob" "124 Conch Street")

@addresses ;=> {"Spongebob" "124 Conch Street"}
(slurp "/tmp/addresses.clj") ;=> {"Spongebob" "124 Conch Street"}

Example: PostgreSQL-backed

(ns your-ns
  (:require [alandipert.enduro :as e]
            [alandipert.enduro.pgsql :as pg]
            [clojure.java.jdbc :as sql])

;; In this example, which is compatible with usage on Heroku, we first
;; define a function to return different connection information
;; depending on whether or not DATABASE_URL is defined. If it is, we
;; are likely on Heroku and the connection information is defined for
;; us. Otherwise, we'll connect to a local PostgreSQL database.

(defn db-config []
  (or (System/getenv "DATABASE_URL") "postgresql://localhost:5432/your-db"))

;; Call e/postgresql-atom with a value, a database connection string
;; or configuration map per clojure.java.jdbc, and the name of a table
;; to use to store the atom's value.

;; We wrap the atom in a delay to prevent a connection attempt during
;; ahead-of-time compilation, as enduro atoms attempt to commit their
;; initialization value as soon as they are created.

(def addresses
  (delay
   (pg/postgresql-atom
    {}
    (db-config)
    "enduro")))

;; Note: We assume for the remainder of this example that all calls
;; occur inside functions in order to prevent compile-time database
;; connection attempts.

;; In this call to `swap!` we're derefencing the delay, not the
;; atom.

(e/swap! @addresses assoc "Spongebob" "124 Conch Street")

;; To see the atom's value, it must be dereferenced twice to account
;; for the delay.

@@addresses ;=> {"Spongebob" "124 Conch Street"}

;; You can inspect the table enduro is using with clojure.java.jdbc.

(sql/with-connection (db-config)
  (sql/with-query-results rows
    [(str "SELECT value FROM enduro LIMIT 1")]
    (read-string (:value (first rows)))))

;=> {"Spongebob" "124 Conch Street"}

Notes

Development

This project is built, tested, and deployed using boot.

Run tests: boot test Run tests continuously with audio feedback: boot watch speak test

Appropriate Usage

Because enduro must write the entire atom contents on every swap!, writes are very slow compared to a real database. Enduro atoms, despite being disk or database-backed, must fit in memory. Use with very small data only.

In-transaction Data Recovery

File-backed enduro atoms use temporary files to store in-transaction data and depend on the atomicity of java.nio.Files/move.

If a transaction fails exceptionally or irrecoverably, the (likely corrupt) in-transaction data can be found in your :pending-dir directory with a name like enduro_pending5327124809540815880.clj.

Currently, PostgreSQL-backed atoms do not persist failed transaction data.

Resource Management

Enduro makes no attempt to prevent you from allocating some underlying resource, whether file or PostgreSQL table, to multiple atoms.

Enduro also provides no mechanism for deallocating resources, so you cannot reliably use the same resource for different atoms in the same program.

Be sure not to modify resources in use by enduro from either inside your program or elsewhere while your program is running.

License

Copyright ยฉ 2012 Alan Dipert

Distributed under the Eclipse Public License, the same as Clojure.

The photo "enduro_rois_3" in this README is copyright ยฉ 2009 Josรฉ Arufe and made available under a Creative Commons license.

More Repositories

1

ncsa-mosaic

NCSA Mosaic 2.7
C
626
star
2

gherkin

a functional programming language and interpreter written in GNU Bash 4
Shell
522
star
3

storage-atom

ClojureScript atoms backed by HTML5 web storage.
Clojure
194
star
4

intension

Query nested maps/vectors with Datalog
Clojure
160
star
5

clj-swingrepl

Clojure REPL GUI using Swing
Java
40
star
6

html2r

Convert HTML to R
R
36
star
7

hyperturbo

Clojure
24
star
8

berrycam

A small Clojure webcam server for the Raspberry Pi.
Clojure
19
star
9

fclojure

Minimal Clojure-like interpreter with FEXPRs
Clojure
16
star
10

dotfiles

Sundry configs and whatnots
Emacs Lisp
15
star
11

reconfig

Reload configuration files in Clojure daemons on SIGHUP.
Clojure
14
star
12

campfireclient

Java API and command-line client for Campfire, the 37Signals chat application.
Java
12
star
13

flapjax-demo

ClojureScript/Flapjax FRP Demo
Clojure
11
star
14

jsonptunnel

C (F)CGI for tunneling POST over GET for cross-site JSONP POST requests
C
11
star
15

interpol8

Ruby-style string interpolation
Clojure
11
star
16

desiderata

A Clojure and ClojureScript bag of tricks.
Clojure
10
star
17

fast-shiny

My rstudio::conf 2018 presentation slides
M4
10
star
18

tdd-bytecode

TDD Java bytecode with Boot
Jasmin
10
star
19

embedded-hoplon-example

Example of attaching a Hoplon component to a mount point in an existing HTML page.
Clojure
10
star
20

rns

A namespacing library supporting functional programming in Ruby
Ruby
9
star
21

alan-emacs.d

My emacs thingy
Emacs Lisp
9
star
22

lbbasic

Little Bird BASIC
Clojure
7
star
23

resource-js

a Javascript clone of the awesome RestClient::Resource
JavaScript
6
star
24

mathemagician

Automatically generate Clojure function proxies for java.lang.Math static methods.
Clojure
5
star
25

hoplon-contacts-demo

Simple contacts application with Boot 2 and Hoplon 6
Clojure
5
star
26

boot-yeti

A Boot task for compiling Yeti source
Clojure
5
star
27

react-widget-demo

JavaScript
5
star
28

jtemplate

Java project scaffolding with Ant - automatic executable Jar with included dependency resources
5
star
29

lector

Ruby data parser
Ruby
5
star
30

clj-mockito

Clojure wrapper for the Mockito mocking library
Clojure
5
star
31

boot-java-task-example

Example of a task that depends on Java compilation with boot-clj
Clojure
5
star
32

stubwatch

Stub out inotify_add_watch(2) calls with LD_PRELOAD
C
4
star
33

wondr-blog

Source code for my R blog
CSS
4
star
34

pantless

a tiny lisp1 with macros that compiles to JS
JavaScript
4
star
35

ruby-aws

This fork of Ruby/AWS lets you set your secret ID in the constructor of Request
Ruby
4
star
36

tailnote

like tail -f, but matches lines and growls them
4
star
37

e2j

Command-line tool for converting between EDN and JSON
Clojure
4
star
38

golf

The Golf Application Server
Java
4
star
39

oscon2012-clojure

Emacs Lisp
3
star
40

docker-mlton

A Docker image for mlton, the whole program optimizing compiler for Standard ML.
Standard ML
3
star
41

gitrubytesting-presentation

A slidedown presentation on git and ruby testing
3
star
42

alandipert.github.com

JavaScript
3
star
43

minirpn

Small command-line RPN calculator in C
C
3
star
44

fl

Function Level programming library for Clojure
Clojure
3
star
45

hoptoad

(work in progress) Ring middleware for sending exceptions to Hoptoad
Clojure
3
star
46

prompt_pwd

Print the current working directory, shortened to fit the prompt
C
3
star
47

avltree

Experimental immutable AVL tree implementation in R
R
2
star
48

boot-trinkets

My odd collection of boot tasks and utilities.
Clojure
2
star
49

boat

Perl
2
star
50

bellona

Experiments with Lisp-style macros in C using cmacro
C
2
star
51

fortunefinder

A baby project to help me learn the basics of Sinatra
Ruby
2
star
52

shave

a wannabe lisp interpreter
C
2
star
53

esl-lab

Experiments with eslisp
Common Lisp
2
star
54

clj-utils

Alan's Close Personal Clojure Functions
Clojure
2
star
55

hoplon-minesweeper

Unfinished Minesweeper in Hoplon
Clojure
2
star
56

just-lisp-things

Emacs Lisp
2
star
57

scala-presentation

Scala presentation for Rochester Hackers meetup
Scala
2
star
58

advent-of-code-2019

My solutions to https://adventofcode.com/2019/
Common Lisp
2
star
59

rails-jsonservicegenerator

This is a quick fork of Rails's boxed 'scaffold' generator that computes JSON by default, along with xml/html
Ruby
2
star
60

interlock-www

Interlock, the Rochester Hackerspace nanoc site
Ruby
2
star
61

triclojure-hoplon-deck

Slides for a Hoplon presentation at TriClojure
JavaScript
2
star
62

blinky

Blink LED on pin 13 on an Arduino NG
C
2
star
63

hoplon-getenv-example

Clojure
1
star
64

advent-of-code-2017

http://adventofcode.com/ solutions in R and Common Lisp
Common Lisp
1
star
65

hoplon-datatable-example

Example of using jQuery DataTable with Hoplon
Clojure
1
star
66

barcamp2012-jsonscript

Your Own Compiler in 20 Minutes: a Rochester BarCamp Oct. 2012 Presentation
Emacs Lisp
1
star
67

gherkin2

wip... shhh...
Shell
1
star
68

enduro-todo

todoFRP with Flapjax for FRP and enduro for server persistence
JavaScript
1
star
69

shout2

Sinatra, CoffeeScript, and homegrown polling
JavaScript
1
star
70

boot-javaloader-example

Program with entrypoint for both Clojure (slow) and Java (fast) - for writing server/client type things
Java
1
star
71

advent-of-code-2018

My solutions to https://adventofcode.com/2018
Common Lisp
1
star
72

skirmish

Clojure
1
star
73

abcl-maven-plugin

Maven plugin for Armed Bear Common Lisp
Java
1
star
74

gitgoggle

A goggle for GitHub issues
Clojure
1
star
75

boggle-solver

Boggle solver in Hoplon
Clojure
1
star
76

cljs-priority-map

PersistentPriorityMap for ClojureScript
Clojure
1
star
77

advent-of-code-2015

Solutions to advent of code in Clojure
Clojure
1
star
78

engineyard-contest

A C program for computing Hamming distances of random strings (for the EngineYard SHA1 contest)
C
1
star
79

constrained-checkboxes-hoplon

Example of constrained checkboxes in Hoplon
Clojure
1
star
80

boot-cljs-reload-problem

Test repo
Clojure
1
star