https://github.com/iaintshine/social_coffee
Thrift service used for querying friendships and user's relationships
https://github.com/iaintshine/social_coffee
Last synced: 3 months ago
JSON representation
Thrift service used for querying friendships and user's relationships
- Host: GitHub
- URL: https://github.com/iaintshine/social_coffee
- Owner: iaintshine
- License: mit
- Created: 2014-08-06T20:19:24.000Z (almost 11 years ago)
- Default Branch: master
- Last Pushed: 2014-08-11T15:47:24.000Z (almost 11 years ago)
- Last Synced: 2025-02-04T14:47:58.092Z (5 months ago)
- Language: JavaScript
- Size: 613 KB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE.txt
Awesome Lists containing this project
README
# Social Coffee
*Social Coffee* is a Thrift service used for querying friendships and user's relationships.
It is written in Node.js using Coffeescript and stores data in Redis key-value NoSQL store.
Comes with client libraries written for Python, Ruby and Node. In addition to multiple client libraries
it comes with `social-cli` - interactive command utility.## Goals
It supports very simple operations and tries to solve very few problems, but it's designed for on-line, low-latency
and high-throughput.* a high rate of query/add/remove operations
* potentially complex *set* arithmentic operations
* horizontal scaling
* sharding
* consistent## Non - goals
* multi-hop or graph-walking queries
## Operations
The service supports fairly simple operations and it's used to store a symmetrical social graph, where if a user A is a friend with a user B, then symmetrically a user B is a friend with a user A. For each friendship relationship operation there are two rows written into the backing store.
```
users:1:friends -> [ 2 ]
users:2:friends -> [ 1 ]
```1. Query friends list.
Synopsis:
```
list get_friends(1: ID id) throws (1: SocialException ex)
```Returns a list of user's friends with provided ID.
Params:
* `id` - The ID of the user for whom the list of the friends should be retrieved.Return:
* The list of user's friends IDs. If user has no friends empty list is returned.Throws:
`SocialException` if
* ID is null
* ID is not a number
* ID is a non positive number
* internall error occurs, e.g. connection to a database could not be establishedExample:
```ruby
client.get_friends 1
```2. Create friendship between two users
Synopsis:
```
bool create_friendship(1: ID usera, 2: ID userb) throws (1: SocialException ex)
```Asks the service to make a new multual friendship relationship between users with IDs usera and userb.
It's an idempotent operation so it can be called multiple times.Params:
* `usera` - The ID of the user A.
* `userb` - The ID of the user B.Return:
* Boolean value indicating whether the operation created a new relationship or relationship already existed. "true" if operation created a new friendship relationship, "false" otherwise.Throws:
`SocialException` if
* any of IDs is null
* any of IDs is not a number
* any of IDs is a non positive number
* both of IDs are equal
* internall error occurs, e.g. connection to a database could not be establishedExample:
```ruby
client.create_friendship 1, 2
```3. Remove friendship between two users
Synopsis:
```
bool remove_friendship(1: ID usera, 2: ID userb) throws (1: SocialException ex)
```Asks the service to remove a new friendship relationship between users with IDs usera and userb.
It's an idempotent operation so it can be called multiple times.Params:
* `usera` - The ID of the user A.
* `userb` - The ID of the user B.Return:
* Boolean value indicating whether the operation removed an already existed relationship or operation did nothing. "true" if operation removed an already existed friendship relationship, "false" otherwise.Throws:
`SocialException` if
* any of IDs is null
* any of IDs is not a number
* any of IDs is a non positive number
* both of IDs are equal
* internall error occurs, e.g. connection to a database could not be establishedExample:
```ruby
client.remove_friendship 1, 2
```## Installation
### Runtime Requirements
To operate properly Social Coffee service requires
* `Node.js` platform
* and access to `Redis` key-value data store### Service Requirements
Installation of server's required packages is as simple as calling
$ npm install
## Running
### Configuration
All required configuration files are found under `config/` directory and use YAML format. For now there is only a single configuration file required called `db.yaml`.
`db.yaml` contains a database configuration (here Redis) for every runtime environment (e.g. development, test, production, staging). If redis is installed on a `localhost` with default configuration creating database configuration file is as simple as calling:
$ cp config/db.yaml.example config/db.yaml
Parameters:
* `host`, string, required, URL of the host machine where Redis is installed
* `port`, number, required, the port number of a Redis instance
* `password`, string, optional, if a Redis instance is password-protected, password required for authentication### Starting the Server
By default the server ships with four enviornments: "development", "test", "staging" and "production".
If no environment is specified the server starts in development environemnt. So calling:$ node lib/index.js
starts the server bound to host `0.0.0.0`, port `9090` and in `development` environment.
To change an environemnt use `NODE_ENV` environment variable. E.g. to start the server in `production` enviornment on port `3000` execute:
$ NODE_ENV=production node lib/index.js -p 3000Options:
* `-p`, `--port`, `number`, default: `9090`, the port number
## CLI
*Social Coffee* service is delivered with a command line tool similar `redis-cli` that works in REPL manner.
`social-cli` supports tab autocompletion and comes with just two options. The first one specifies a port number
and the second one specifies a host to which thrift client should connect.### Options
* `-p`, `--port`, `number`, default: `9090`, port number
* `-h`, `--hort`, `string`, default: `localhost`, host address### Command list
* `ping` - utility command used for asking if we still have a connection to a remote server. If the client is connected to
thrift's server it will respond with `"pong"` string, displayd in a console.
* `server info` - the command asks a remote server for thrift server description.
* `server counters` - the command asks a remote server for performance counters.
* `server options` - the command asks a remote server for server options/configuration.
* `friends list id` - the command queries a remote server for user's friends list. If a user has friends than the list of user's friends IDs is displayed, empty array otherwise.
* `friendship create id_a id_b` - the command asks a remote server to make a new mutual friendship relationship between users with IDs `id_a` and `id_b`. The command call displays a message indicating whether or not the operation performed created a new
friendship relationship or relationship already existed and did nothing.
* `friendship remove id_a id_b` - the command asks a remote server to remove a friendship relationship between users with IDs `id_a` and `id_b`. The command call displays a message indicating whether or not the operation performed removed existed friendship relationship or did nothing.
* `quit`, `exit` - the command disconnects thrift's client from remote server and shuts down cli.### Sample session
Below code shows a sample session from interaction with `social-cli` command line tool.
```
localhost:9000>info: client connected to remote server
localhost:9000>ping
pong
localhost:9000>friends list 1
[]
localhost:9000>friendship create 1 2
friendship newely created: true
localhost:9000>friends list 1
[ 2 ]
localhost:9000>friendship remove 1 2
friendship just removed: true
localhost:9000>friends list 1
[]
localhost:9000>quit
bye bye...
```## Clients
The sever except for `social-cli` command line tool comes with multiple client libraries written for Python, Ruby and Node.js (using Coffeescript).
### Ruby
See [the offical Social Coffee Ruby client documentation](https://github.com/iaintshine/social_coffee/tree/master/client/ruby)
### Python
See [the offical Social Coffee Python client documentation](https://github.com/iaintshine/social_coffee/tree/master/client/python)
### Node.js
It is not exposed as a package but instead used internally by the `social-cli` command line tool.
* [Client definition](https://github.com/iaintshine/social_coffee/blob/master/src/thrift/client.coffee)
* [Client usage](https://github.com/iaintshine/social_coffee/blob/master/src/cli.coffee)## Testing
### Unit Testing
To run unit tests execute:
$ npm test
### Load Testing
For more information about how to load test the thrift service using Locust see [load testing](https://github.com/iaintshine/social_coffee/tree/master/locust)
## Development
### Requirements
1. Globally install Coffeescript compiler
$ [sudo] npm install -g coffeescript
2. Globally install Cake
$ [sudo] npm install -g cake
3. If you are going to generate documentation, globally install groc
$ [sudo] npm install -g groc
4. If you are going to regenerate and change thrift interfaces install Thrift compiler with support for at least Node.js, Ruby and Python. [Apache Thrift](https://thrift.apache.org)
Now if all the above requirements are installed execute `watch` cake task to watch `src/` directory for changes and compile `*.coffee` files into `*.js` equivalent.
$ cake watch
### Cake Tasks
* `watch` - the task used for watching for Coffeescript file changes and recompilation to Javascript.
* `generate:thrift` - the task used for generating thrift bindings for Node.js, Python, Ruby and human-readable HTML documentation generation from thrift interfaces stored under `thrift/` directory.E.g. to regenerate thrift bindings simply call:
$ cake generate:thrift
## Provisioning
For more information about how to provision the service using Ansible see [provision](https://github.com/iaintshine/social_coffee/tree/master/provision)
## Documentation
The documentation generated from the source code can be found under `doc/` directory, whereas the documentation generated from the thrift interfaces is located under `doc/thrift/` directory.
## What's missing
* Server Clustering
* Redis Automatic failover with sentinel
* Database model support for replication with master/multiple slaves
* Multiple Redis instances sharding
* Distributed transactions support with Two-phase Commit Protocol. Instead of writing a coordinator to handle distributed transactions we might choose to use e.g. Hyperdex data store which supports distirbuted transactions with it's own WARP protocol.## Contributing
1. Fork it
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create new Pull Request