{"id":13508820,"url":"https://github.com/wooga/eredis","last_synced_at":"2025-08-24T14:31:44.909Z","repository":{"id":44461030,"uuid":"1586693","full_name":"wooga/eredis","owner":"wooga","description":"Erlang Redis client","archived":true,"fork":false,"pushed_at":"2023-03-27T10:48:11.000Z","size":302,"stargazers_count":630,"open_issues_count":28,"forks_count":281,"subscribers_count":214,"default_branch":"master","last_synced_at":"2025-04-25T12:54:06.438Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Erlang","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wooga.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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":"2011-04-08T09:54:32.000Z","updated_at":"2025-04-17T16:36:14.000Z","dependencies_parsed_at":"2022-07-20T09:02:05.123Z","dependency_job_id":"d54a6271-2868-47ff-9832-27260f691454","html_url":"https://github.com/wooga/eredis","commit_stats":null,"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"purl":"pkg:github/wooga/eredis","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wooga%2Feredis","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wooga%2Feredis/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wooga%2Feredis/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wooga%2Feredis/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wooga","download_url":"https://codeload.github.com/wooga/eredis/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wooga%2Feredis/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271887599,"owners_count":24839135,"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","status":"online","status_checked_at":"2025-08-24T02:00:11.135Z","response_time":111,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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-08-01T02:00:58.955Z","updated_at":"2025-08-24T14:31:44.577Z","avatar_url":"https://github.com/wooga.png","language":"Erlang","funding_links":[],"categories":["ORM and Datamapping","Erlang"],"sub_categories":["C++"],"readme":"# eredis\n\nNon-blocking Redis client with focus on performance and robustness.\n\nSupported Redis features:\n\n * Any command, through eredis:q/2\n * Transactions\n * Pipelining\n * Authentication \u0026 multiple dbs\n * Pubsub\n\n## Example\n\nIf you have Redis running on localhost, with default settings, you may\ncopy and paste the following into a shell to try out Eredis:\n\n    git clone git://github.com/wooga/eredis.git\n    cd eredis\n    ./rebar compile\n    erl -pa ebin/\n    {ok, C} = eredis:start_link().\n    {ok, \u003c\u003c\"OK\"\u003e\u003e} = eredis:q(C, [\"SET\", \"foo\", \"bar\"]).\n    {ok, \u003c\u003c\"bar\"\u003e\u003e} = eredis:q(C, [\"GET\", \"foo\"]).\n\nTo connect to a Redis instance listening on a Unix domain socket:\n\n    {ok, C1} = eredis:start_link({local, \"/var/run/redis.sock\"}, 0).\n\nMSET and MGET:\n\n```erlang\nKeyValuePairs = [\"key1\", \"value1\", \"key2\", \"value2\", \"key3\", \"value3\"].\n{ok, \u003c\u003c\"OK\"\u003e\u003e} = eredis:q(C, [\"MSET\" | KeyValuePairs]).\n{ok, Values} = eredis:q(C, [\"MGET\" | [\"key1\", \"key2\", \"key3\"]]).\n```\n\nHASH\n\n```erlang\nHashObj = [\"id\", \"objectId\", \"message\", \"message\", \"receiver\", \"receiver\", \"status\", \"read\"].\neredis:q(C, [\"HMSET\", \"key\" | HashObj]).\n{ok, Values} = eredis:q(C, [\"HGETALL\", \"key\"]).\n```\n\nLIST\n\n```erlang\neredis:q(C, [\"LPUSH\", \"keylist\", \"value\"]).\neredis:q(C, [\"RPUSH\", \"keylist\", \"value\"]).\neredis:q(C, [\"LRANGE\", \"keylist\",0,-1]).\n```\n\nTransactions:\n\n```erlang\n{ok, \u003c\u003c\"OK\"\u003e\u003e} = eredis:q(C, [\"MULTI\"]).\n{ok, \u003c\u003c\"QUEUED\"\u003e\u003e} = eredis:q(C, [\"SET\", \"foo\", \"bar\"]).\n{ok, \u003c\u003c\"QUEUED\"\u003e\u003e} = eredis:q(C, [\"SET\", \"bar\", \"baz\"]).\n{ok, [\u003c\u003c\"OK\"\u003e\u003e, \u003c\u003c\"OK\"\u003e\u003e]} = eredis:q(C, [\"EXEC\"]).\n```\n\nPipelining:\n\n```erlang\nP1 = [[\"SET\", a, \"1\"],\n      [\"LPUSH\", b, \"3\"],\n      [\"LPUSH\", b, \"2\"]].\n[{ok, \u003c\u003c\"OK\"\u003e\u003e}, {ok, \u003c\u003c\"1\"\u003e\u003e}, {ok, \u003c\u003c\"2\"\u003e\u003e}] = eredis:qp(C, P1).\n```\n\nPubsub:\n\n```erl\n1\u003e eredis_sub:sub_example().\nreceived {subscribed,\u003c\u003c\"foo\"\u003e\u003e,\u003c0.34.0\u003e}\n{\u003c0.34.0\u003e,\u003c0.37.0\u003e}\n2\u003e eredis_sub:pub_example().\nreceived {message,\u003c\u003c\"foo\"\u003e\u003e,\u003c\u003c\"bar\"\u003e\u003e,\u003c0.34.0\u003e}\n```\n\nPattern Subscribe:\n    \n```erl\n1\u003e eredis_sub:psub_example(). \nreceived {subscribed,\u003c\u003c\"foo*\"\u003e\u003e,\u003c0.33.0\u003e}\n{\u003c0.33.0\u003e,\u003c0.36.0\u003e}\n2\u003e eredis_sub:ppub_example().\nreceived {pmessage,\u003c\u003c\"foo*\"\u003e\u003e,\u003c\u003c\"foo123\"\u003e\u003e,\u003c\u003c\"bar\"\u003e\u003e,\u003c0.33.0\u003e}\nok\n3\u003e \n```\n\nEUnit tests:\n\n```console\n./rebar eunit\n```\n\n\n## Commands\n\nEredis has one main function to interact with redis, which is\n`eredis:q(Client::pid(), Command::iolist())`. The response will either\nbe `{ok, Value::binary() | [binary()]}` or `{error,\nMessage::binary()}`.  The value is always the exact value returned by\nRedis, without any type conversion. If Redis returns a list of values,\nthis list is returned in the exact same order without any type\nconversion.\n\nTo send multiple requests to redis in a batch, aka. pipelining\nrequests, you may use `eredis:qp(Client::pid(),\n[Command::iolist()])`. This function returns `{ok, [Value::binary()]}`\nwhere the values are the redis responses in the same order as the\ncommands you provided.\n\nTo start the client, use any of the `eredis:start_link/0,1,2,3,4,5,6,7`\nfunctions. They all include sensible defaults. `start_link/7` takes\nthe following arguments:\n\n* Host, dns name or ip adress as string; or unix domain socket as {local, Path} (available in OTP 19+)\n* Port, integer, default is 6379\n* Database, integer or 0 for default database\n* Password, string or empty string([]) for no password\n* Reconnect sleep, integer of milliseconds to sleep between reconnect attempts\n* Connect timeout, timeout value in milliseconds to use in `gen_tcp:connect`, default is 5000\n* Socket options, proplist of options to be sent to `gen_tcp:connect`, default is `?SOCKET_OPTS`\n\n## Reconnecting on Redis down / network failure / timeout / etc\n\nWhen Eredis for some reason looses the connection to Redis, Eredis\nwill keep trying to reconnect until a connection is successfully\nestablished, which includes the `AUTH` and `SELECT` calls. The sleep\ntime between attempts to reconnect can be set in the\n`eredis:start_link/5` call.\n\nAs long as the connection is down, Eredis will respond to any request\nimmediately with `{error, no_connection}` without actually trying to\nconnect. This serves as a kind of circuit breaker and prevents a\nstampede of clients just waiting for a failed connection attempt or\n`gen_server:call` timeout.\n\nNote: If Eredis is starting up and cannot connect, it will fail\nimmediately with `{connection_error, Reason}`.\n\n## Pubsub\n\nThanks to Dave Peticolas (jdavisp3), eredis supports\npubsub. `eredis_sub` offers a separate client that will forward\nchannel messages from Redis to an Erlang process in a \"active-once\"\npattern similar to gen_tcp sockets. After every message sent, the\ncontrolling process must acknowledge receipt using\n`eredis_sub:ack_message/1`.\n\nIf the controlling process does not process messages fast enough,\neredis will queue the messages up to a certain queue size controlled\nby configuration. When the max size is reached, eredis will either\ndrop messages or crash, also based on configuration.\n\nSubscriptions are managed using `eredis_sub:subscribe/2` and\n`eredis_sub:unsubscribe/2`. When Redis acknowledges the change in\nsubscription, a message is sent to the controlling process for each\nchannel.\n\neredis also supports Pattern Subscribe using `eredis_sub:psubscribe/2`\nand `eredis_sub:unsubscribe/2`. As with normal subscriptions, a message\nis sent to the controlling process for each channel.\n\nAs of v1.0.7 the controlling process will be notified in case of\nreconnection attempts or failures. See `test/eredis_sub_tests` for\ndetails.\n\n## AUTH and SELECT\n\nEredis also implements the AUTH and SELECT calls for you. When the\nclient is started with something else than default values for password\nand database, it will issue the `AUTH` and `SELECT` commands\nappropriately, even when reconnecting after a timeout.\n\n\n## Benchmarking\n\nUsing basho_bench(https://github.com/basho/basho_bench/) you may\nbenchmark Eredis on your own hardware using the provided config and\ndriver. See `priv/basho_bench_driver_eredis.config` and\n`src/basho_bench_driver_eredis.erl`.\n\n## Queueing\n\nEredis uses the same queueing mechanism as Erldis. `eredis:q/2` uses\n`gen_server:call/2` to do a blocking call to the client\ngen_server. The client will immediately send the request to Redis, add\nthe caller to the queue and reply with `noreply`. This frees the\ngen_server up to accept new requests and parse responses as they come\non the socket.\n\nWhen data is received on the socket, we call `eredis_parser:parse/2`\nuntil it returns a value, we then use `gen_server:reply/2` to reply to\nthe first process waiting in the queue.\n\nThis queueing mechanism works because Redis guarantees that the\nresponse will be in the same order as the requests.\n\n## Response parsing\n\nThe response parser is the biggest difference between Eredis and other\nlibraries like Erldis, redis-erl and redis_pool. The common approach\nis to either directly block or use active once to get the first part\nof the response, then repeatedly use `gen_tcp:recv/2` to get more data\nwhen needed. Profiling identified this as a bottleneck, in particular\nfor `MGET` and `HMGET`.\n\nTo be as fast as possible, Eredis takes a different approach. The\nsocket is always set to active once, which will let us receive data\nfast without blocking the gen_server. The tradeoff is that we must\nparse partial responses, which makes the parser more complex.\n\nIn order to make multibulk responses more efficient, the parser\nwill parse all data available and continue where it left off when more\ndata is available.\n\n## Future improvements\n\nWhen the parser is accumulating data, a new binary is generated for\nevery call to `parse/2`. This might create binaries that will be\nreference counted. This could be improved by replacing it with an\niolist.\n\nWhen parsing bulk replies, the parser knows the size of the bulk. If the\nbulk is big and would come in many chunks, this could improved by\nhaving the client explicitly use `gen_tcp:recv/2` to fetch the entire\nbulk at once.\n\n## Credits\n\nAlthough this project is almost a complete rewrite, many patterns are\nthe same as you find in Erldis, most notably the queueing of requests.\n\n`create_multibulk/1` and `to_binary/1` were taken verbatim from Erldis.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwooga%2Feredis","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwooga%2Feredis","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwooga%2Feredis/lists"}