Redis: why MOVED to another master - redis

I've a Redis cluster - 3 masters and 3 slaves. This cluster contains ~300 keys(foo0 - foo300). I understand that each master responsible for certain subset of data and can redirect client to right node with MOVED error.
But, If I send request to GET nonexisting keys(like klsdkaso, qwerty123 ...) from master, I also got MOVED to another node. I'm confused. Who can explain why so?

In order to make it clear, let's define two kinds of master nodes:
Connected Node: The node that your client connecting to, and you are sending GET command to this node.
Destination Node: The node that the given key SHOULD be located, i.e. the one you are redirected or moved to.
Because the Connected Node only has the slot-mapping information, i.e. the given key SHOULD be located on the Destination Node. However, it DOES NOT know whether the given key exists on Destination Node.
So the Connected Node has to redirect the client to the Destination Node first, i.e. use the MOVED error message to give the IP and port information on the Destination Node. Then the client sends another GET command to the Destination Node to check whether the given key really exists.

A key, whether it actually exists or not, is mapped by hashing its name (or parts of it, a.k.a tags) to a slot. Slots are assigned to masters, and a master first checks for a key's "belongingness" to it (in terms of the current slot ranges assignments) and only then performs any other operations.

Related

How to handle delete booking webtours in jmeter?

How to handle the remove flight booking in webtours? It came to my mind that if I wanna run the test with 3 virtual users and how they supposed to delete the booking if the information down here (refer below) are unique for each virtual user? Does any of these variables below need to be parameterized or need to apply correlation?
If there are multiple flight id to be deleted, we can create a CSV file having those ids
and use a while loop controller to delete each of them.
You may refer -
https://guide.blazemeter.com/hc/en-us/articles/206733689-Using-CSV-DATA-SET-CONFIG
https://www.blazemeter.com/blog/using-while-controller-jmeter
As you said, it will differ for a different user, you can store each value from the response of each user(extract value using regex) and pass them in delete call.
reference link - https://guide.blazemeter.com/hc/en-us/articles/207421325-Using-RegEx-Regular-Expression-Extractor-with-JMeter-Using-RegEx-(Regular-Expression-Extractor)-with-JMeter
I don't know what "webtours" is, however there is one "golden" rule: each and every parameter which is dynamic needs to be correlated.
If you don't have any idea regarding which ones are dynamic - record the same action one more time using JMeter's HTTP(S) Test Script Recorder and compare the generated requests, parameter values (or even names) which differ needs to be correlated.
Another approach is to inspect the previous response(s) using View Results Tree listener and look if the data is present there
Check out Advanced Load Testing Scenarios with JMeter: Part 1 - Correlations article for more information and example implementation

GoDaddy Deleting a single DNS record through the API using Bash/Shell script

I'd like to delete a single DNS record (an A record) through the API via CURL or any other Shell/Bash command.
I also tried to access GoDaddy's website but unfortunately it no longer exists and returns 404.
https://www.godaddy.com/community/Managing-Domains/Deleting-a-single-DNS-record-through-the-API/td-p/108003
Is it possible, how can I do that?
EDIT The original answer seems to be obsolete
GoDaddy has added the respective endpoint to delete a single entry. So now you can do
DELETE /v1/domains/{domain}/records/A/{name}
Original answer
Unfortunately, godaddy's api does not provide the endpoint for deleting a single domain record in a single call. So you will have to
GET /v1/domains/{domain}/records/A to fetch all A-records for the domain first (https://developer.godaddy.com/doc/endpoint/domains#/v1/recordGet)
remove the record to delete from the resulting list
PUT /v1/domains/{domain}/records/A the modified recordset to replace all A-records for the domain with the given list of records (https://developer.godaddy.com/doc/endpoint/domains#/)
As the API endpoints return/expect JSON data, you might need some additional tool to manipulate the json data. You might find something in this answer Parsing JSON with Unix tools
You might be tempted to use PUT /v1/domains/{domain}/records/A/{recordname} to replace all A-records with the given name with the provided list of records (https://developer.godaddy.com/doc/endpoint/domains#/v1/recordReplaceTypeName) using an empty list of records in the body. The last time I tried that, it didn't work.

SADD only if SCARD below a value

Node.js & Redis:
I have a LIST (users:waiting) storing a queue of users waiting to join games.
I have SORTED SET (games:waiting) of games waiting for users. This is updated by the servers every 30s with a new date. This way I can ensure if a server crashes, the game is no longer used. If the server is running and fills up, it'll remove itself from the sorted set.
Each game has a SET (game:id:users) containing the users that are in it. Each game can accept no more than 6 players.
Multiple servers are using BRPOP to pick up users from the LIST (users:waiting).
Once a server has a user id, it gets the waiting games ids, then proceeds to run SCARD on their game:id:users SET. If the result of this is less than 6, it adds them to the set.
The problem:
If multiple servers are doing this at once, we could end up with more than 6 users being added to a set at a time. For example if one server requests SCARD and immediately after another runs SADD, the number in the set will have increased but the first server won't know.
Is there anyway of preventing this?
You need transactions, which redis supports: http://redis.io/topics/transactions
in your case in particular, you want to pay attention to the watch command: http://redis.io/topics/transactions#cas

How to clean up inactive players in redis?

I'm making a game that uses redis to store game state. It keeps track of locations and players pretty well, but I don't have a good way to clean up inactive players.
Every time a player moves (it's a semi-slow moving game. Think 1-5 frames per second), I update a hash with the new location and remove the old location key.
What would be the best way to keep track of active players? I've thought of the following
Set some key on the user to expire. Update every heartbeat or move. Problem is the locations are stored in a hash, so if the user key expires the player will still be in the same spot.
Same, but use pub/sub to listen for the expiration and finish cleaning up (seems overly complicated)
Store heartbeats in a sorted set, have a process run every X seconds to look for old players. Update score every heartbeat.
Completely revamp the way I store locations so I can use expire.. somehow?
Any other ideas?
Perhaps use separate redis data structures (though same database) to track user activity
and user location.
For instance, track users currently online separately using redis sets:
[my code snippet is in python using the redis-python bindings, and adapted from example app in Flask (python micro-framework); example app and the framework both by Armin Ronacher.]
from redis import Redis as redis
from time import time
r1 = redis(db=1)
when the function below is called, it creates a key based on current unix time in minutes
and then adds a user to a set having that key. I would imagine you would want to
set the expiry at say 10 minutes, so at any given time, you have 10 keys live
(one per minute).
def record_online(player_id):
current_time = int(time.time())
expires = now + 600 # 10 minutes TTL
k1 = "playersOnline:{0}".format(now//60)
r1.sadd(k1, player_id)
r1.expire(k1, expires)
So to get all active users just union all of the live keys (in this example, that's 10
keys, a purely arbitrary number), like so:
def active_users(listOfKeys):
return r1.sunion(listOfKeys)
This solves your "clean-up" issues because of the TTL--the inactive users would not appear in your live keys because they constantly recycle--i.e., in active users are only keyed to old timestamps which don't persist in this example (but perhaps are written to a permanent store by redis before expiry). In any event, this clears inactive users from your active redis db.

Update an entity inside an aggregate

I was reading a similar question on SO: How update an entity inside Aggregate, but I'm still not sure how a user interface should interact with entities inside an aggregate.
Let's say I have a User, with a bunch of Addresses. User is the aggregate root, while Address only exists within the aggregate.
On a web inteface, a user can edit his addresses. Basically, what happens is:
The user sees a list of addresses on its web interface
He clicks on an address, and gets redirected to this page: edit-address?user=1&address=2
On this page, he gets a form where he can modify this address.
I we decided to bypass the aggregate root, this would be straightforward:
We would directly load the Address with its Id
We would update it, then save it
Because we want to do it the DDD way, we have different solutions:
Either we ask the User to get this Address by Id:
address = user.getAddress(id);
address.setPostCode("12345");
address.setCity("New York");
em.persist(user);
The problem with this approach is, IMO, that the aggregate root still doesn't have much more control over what's done with the address. It just returns a reference to it, so that's not much different from bypassing the aggregate.
Or we tell the aggregate to update an existing address:
user.updateAddress(id, "12345", "New York");
em.persist(user);
Now the aggregate has control over what's done with this address, and can take any necessary action that goes with updating an address.
Or we treat the Address as a value object, and we don't update our Address, but rather delete it and recreate it:
user.removeAddress(id);
address = new Address();
address.setPostCode("12345");
address.setCity("New York");
user.addAddress(address);
em.persist(user);
This last solution looks elegant, but means that an Address cannot be an Entity. Then, what if it needs to be treated as an entity, for example because another business object within the aggregate has a reference to it?
I'm pretty sure I'm missing something here to correctly understand the aggregate concept and how it's used in real life examples, so please don't hesitate to give your comments!
No, you're not missing anything - in most cases the best option would be number 2 (although I'd call that method changeAddress instead of updateAdress - update seems so not-DDD) and that's regardless whether an address is an Entity or Value Object. With Ubiquitous Language you'd rather say that User changed his address, so that's exactly how you should model it - it's the changeAddress method that gets to decide whether update properties (if Address is an Entity) or assign completely new object (when it's VO).
The following sample code assumes the most common scenario - Address as VO:
public void ChangeAddress(AddressParams addressParams)
{
// here we might include some validation
address = new Address(addressParams);
// here we might include additional actions related with changing address
// for example marking user as required to confirm address before
// next billing
}
What is important in this sample, is that once Address is created, it is considered valid - there can be no invalid Address object in your aggregate. Bare in mind however, that whether you should follow this sample or not depends on your actual domain - there's no one path to follow. This one is the most common one though.
And yes, you should always perform operations on your entities by traversing through aggregate root - the reason for this was given in many answers on SO (for example in this Basic Aggregate Question).
Whether something is an entity or VO depends on the requirements and your domain. Most of the time address is just a Value Object, because there's no difference between two addresses with the same values and addresses tend to not change during their lifetime. But again, that's most of the time and depends on domain you're modeling.
Another example - for most of the domains a Money would be a Value Object - 10$ is 10$, it has no identity besides amount. However if you'd model a domain that deals with money on a level of bills, each bill would have its own identity (expressed with a unique number of some sort) thus it would be an Entity.