{"id":13442541,"url":"https://github.com/vseloved/cl-redis","last_synced_at":"2025-03-20T14:31:20.754Z","repository":{"id":701639,"uuid":"347469","full_name":"vseloved/cl-redis","owner":"vseloved","description":"Redis client for Common Lisp","archived":false,"fork":false,"pushed_at":"2025-02-06T11:29:17.000Z","size":181,"stargazers_count":190,"open_issues_count":5,"forks_count":39,"subscribers_count":10,"default_branch":"master","last_synced_at":"2025-02-06T12:30:55.697Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Common Lisp","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vseloved.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2009-10-23T17:28:23.000Z","updated_at":"2025-02-06T11:29:24.000Z","dependencies_parsed_at":"2023-07-05T15:17:02.444Z","dependency_job_id":null,"html_url":"https://github.com/vseloved/cl-redis","commit_stats":{"total_commits":95,"total_committers":16,"mean_commits":5.9375,"dds":"0.35789473684210527","last_synced_commit":"7d592417421cf7cd1cffa96043b457af0490df7d"},"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vseloved%2Fcl-redis","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vseloved%2Fcl-redis/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vseloved%2Fcl-redis/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vseloved%2Fcl-redis/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vseloved","download_url":"https://codeload.github.com/vseloved/cl-redis/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244630156,"owners_count":20484325,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T03:01:47.035Z","updated_at":"2025-03-20T14:31:20.419Z","avatar_url":"https://github.com/vseloved.png","language":"Common Lisp","readme":"# CL-REDIS — A fast and robust Common Lisp client for Redis\n  (tested with Redis version 3.0.0 (2.9.104 to be precise))\n\n## Usage\n\n### Quickstart\n\n1. Make sure a Redis server is running.\n2. `(ql:quickload 'cl-redis)`\n3. Connect to the server to the given host and port with\n   `(redis:connect :host \u003chost\u003e :port \u003cport\u003e)`\n   (`host` defaults to `127.0.0.1`, `port` — to `6379`).\n4. Interact with the server using Redis commands from the `red` package.\n\n```lisp\nCL-USER\u003e (red:ping)\n\"PONG\"\n```\n\n5. Disconnect from the server with `(redis:disconnect)`.\n6. Alternatively, wrap the whole interaction session in `with-connection` macro,\n   which accepts the same arguments as `connect` does, opens a socket connection,\n   executes the body of the macro with the current connection (`*connection*`)\n   bound to this new connection, and ensures that the connection is closed\n   afterwards.\n\n### Available commands\n\n\n\n### Code organization\n\nThe system provides 2 packages: `REDIS` and `RED`.  All the\nfunctionality is available from the `REDIS` package.  Not to cause\nsymbol clashes, Redis commands are defined in this package with a\nprefix (which defaults to `red-` and is set at compilation time).\nThe package `RED` is a syntactic sugar — it just provides the Redis\ncommands without a prefix.  So it is not intended to be imported to\navoid symbol conflicts with package `COMMON-LISP` — just use the\npackage-qualified symbol names: i.e. the same Redis command (for\ninstance `GET`) can be called as `RED-GET` (if you import the `REDIS` package)\nor `RED:GET`.\n\n\n## Installation\n\nAvailable through [quicklisp](http://quicklisp.org/).\n\n### Dependencies\n\n- [usocket](http://common-lisp.net/project/usocket/)\n- [flexi-streams](http://common-lisp.net/project/flexi-streams/)\n- [rutils](http://github.com/vseloved/rutils)\n- only for tests: [nuts](http://github.com/vseloved/nuts),\n  [bordeaux-threads](http://common-lisp.net/project/bordeaux-threads)\n\n\n## Debugging and error recovery\n\nIf `*echo-p*` is `T`, all client-server communications will be\nechoed to the stream `*echo-stream*`, which defaults to `*standard-output*`.\n\nError handling is mimicked after\n[Postmodern](http://common-lisp.net/project/postmodern/).\nIn particular, whenever an error occurs that breaks the communication stream,\na condition of type `redis-connection-error` is signalled offering\na `:reconnect` restart.  If it is selected the whole Redis command will be\nresent, if the reconnection attempt succeeds.\nFurthermore, `connect` checks if a connection to Redis is already established,\nand offers two restarts (`:leave` and `:replace`) if this is the case.\n\nWhen the server respondes with an error reply\n(i.e., a reply that starts with `-`),\na condition of type `redis-error-reply` is signalled.\n\nThere's also a high-level `with-persistent-connection` macro,\nthat tries to do the right thing™\n(i.e. automatically reopen the connection once, if it is broken).\n\n\n## Advanced usage\n\n### PubSub\n\nSince there's no special command to receive messages from Redis via PubSub\nhere's how you do it:\n\n```lisp\n(bt:make-thread (lambda ()\n                  (with-connection ()\n                    (red:subscribe \"foo\")\n                    (loop :for msg := (expect :anything) :do\n                      (print msg))))\n                \"pubsub-listener\")\n```\n\nTo publish, obviously:\n\n```lisp\n(with-connection ()\n  (red:publish \"foo\" \"test\"))\n```\n\n### Pipelining\n\nFor better performance Redis allows to pipeline commands\nand delay receiving results until the end,\nand process them all in oine batch afterwards.\nTo support that there's `with-pipelining` macro.\nCompare execution times in the following examples\n(with pipelining and without: 6.567 secs vs. 2023.924 secs!):\n\n```lisp\n(let ((names (let (acc)\n               (dotimes (i 1000 (nreverse acc))\n                 (push (format nil \"n~a\" i) acc))))\n      (vals  (let (big-acc)\n               (dotimes (i 1000 (nreverse big-acc))\n                 (let (acc)\n                   (dotimes (i (random 100))\n                     (push (list (random 10) (format nil \"n~a\" i)) acc))\n                   (push (nreverse acc) big-acc))))))\n  (time (redis:with-connection ()\n          (redis:with-pipelining\n            (loop :for k :in names :for val :in vals :do\n              (dolist (v val)\n                (apply #'red:zadd k v)))\n            (red:zunionstore \"result\" (length names) names)\n            (red:zrange \"result\" 0 -1))))\n\n  ;; Evaluation took:\n  ;;  6.567 seconds of real time\n  ;;  3.900243 seconds of total run time (3.200200 user, 0.700043 system)\n\n  (time (redis:with-connection ()\n          (loop :for k :in names :for val :in vals :do\n            (dolist (v val)\n              (apply #'red:zadd k v)))\n          (red:zunionstore \"result\" (length names) names)\n          (red:zrange \"result\" 0 -1))))\n\n  ;; Evaluation took:\n  ;; 2023.924 seconds of real time\n  ;; 3.560222 seconds of total run time (2.976186 user, 0.584036 system)\n```\n\nNote, that `with-pipelining` calls theoretically may nest,\nbut the results will only be available to the highest-level pipeline,\nall the nested pipelines will return :PIPELINED.\nSo a warining is signalled in this situation.\n\n\n## Internals\n\nGeneric functions `tell` and `expect` implement the Redis protocol\naccording to the [spec](http://redis.io/topics/protocol).\n`tell` specifies how a request to Redis is formatted,\n`expect` — how the response is handled.\nThe best way to implement another method on `expect` is usually with\n`def-expect-method`, which arranges reading data from the socket\nand provides a variable `reply`, which holds the decoded reply data\nfrom the server with the initial character removed. For example:\n\n```lisp\n(def-expect-method :ok\n  (assert (string= reply \"OK\"))\n  reply)\n```\n\nRedis operations are defined as ordinary functions by `def-cmd`\nfor which only arguments and return type should be provided.\n`def-cmd` prefixes all the defined functions' names with `*cmd-prefix*`,\nwhich defaults to `'red`.\n(Note, that setting of `*cmd-prefix*` will have its effects at compile time).\nIt also exports them from `REDIS` package,\nand from `RED` package without the prefix.\n\nAn example of command definition is given below:\n\n```lisp\n(def-cmd KEYS (pattern) :multi\n  \"Return all the keys matching the given pattern.\")\n```\n\nSee `commands.lisp` for all defined commands.\n\n\n## Not implemented\n\n- The following commands are not implemented,\n  because they are not intended for use in client:\n  `MONITOR`, `DEBUG OBJECT`, and `DEBUG SEGFAULT`.\n- Support for Unix domain sockets — planned\n- [Consistent hashing](http://en.wikipedia.org/wiki/Consistent_hashing)\n  isn't built-in.  Actually, such thing is orthogonal to the functionality\n  of this library and, probably, should be implemented in a separate library.\n- Connection pooling is also not implemented, because in the presence of\n  `with-persistent-connection` it is actually not needed so much.\n  Persistent connections are more simple, efficient and less error-prone\n  for dedicated threads.  But there are other use-cases for pooling,\n  so it will probably be implemented in future releases.\n\n\n## Credits\n\nThe library is developed and maintained by Vsevolod Dyomkin\n\u003cvseloved@gmail.com\u003e.\n\nAt the initial stages Alexandr Manzyuk \u003cmanzyuk@googlemail.com\u003e\ndeveloped the connection handling code following the implementation in\n[Postmodern](http://common-lisp.net/project/postmodern/). It was since\npartially rewritten to accommodate more advanced connection handling\nstrategies, like persistent connection.\n\n\n## License\n\nMIT (See LICENSE file for details).\n","funding_links":[],"categories":["Common Lisp","Expert Systems"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvseloved%2Fcl-redis","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvseloved%2Fcl-redis","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvseloved%2Fcl-redis/lists"}