How to manage store "created by" in micro-service? - microservices

I am building the inventory service, all tables keep track the owner of each record in column createdBy which store the user id.
The problem is this service does not hold the user info, so it cannot map the id to username which is required for FE to display data.
Calling user service to map the username and userid for each request does not make sense in term of decouple and performance. Because 1 request can ask for maximum 100 records. If I store the username instead of ID, there will be problem when user change their username.
Is there any better way or pattern to solve this problem?

I'd extend the info with the data needed with from the user service.
User name is a slow changing dimension so for most of the time the data is correct (i.e. "safe to cache")
Now we get to what to do when user info changes - this is, of course, a business decision. In some places it makes sense to keep the original info (for example what happens when the user is deleted - do we still want to keep the original user name (and whatever other info) that created the item). If this is not the case, you can use several strategies - you can have a daily (or whatever period) job to go and refresh the users info from the user service for all users used in the inventory, you can publish a daily summary of changes from the user service and have the inventory subscribe to that, you can publish changes as they happen and subscribe to that etc. - depending on the requirement for freshness. The technology to use depends on the strategy..

In my option what you have done so far is correct. Inventory related data should be Inventory Services' responsibility just like user related data should be User Services'.
It is FE's responsibility to fetch the relevant user details from User Service that are required to populate the UI (Remember, call backend for each user is not acceptable at all. Bulk search is more suitable).
What you can do is when you fetch inventory data from Inventory Service, you can publish a message to User Service to notify that "inventory related data was fetched for these users. So there is a possibility to fetch user related data for these users. Therefore you better cache them."
PS - I'm not an expert in microservices architecture. Please add any counter arguments if you have any.*

Related

Re-Ranking Algorithm for Anonymous Users

I have a website:
10,000 pages, each page represent a category, for example: "Laptops".
On each page I am showing 20 recommended products
99% of the users are anonymous
For each user I have a context (device, user-agent and category)
For each product I have the price and the seller name
I have 2 events: outbound & purchase
I would like to re-rank (re-order, sort) the results for each new anonymous user based on the user context. I would like to re-rank based on performance (outbound & purchase).
Do you have recommendation for Specific algorithm OR tool OR service to do that? I found AWS Personalize very nice but the problem is that all of my users are anonymous so I don't believe it can be effective in my use case.
Amazon Personalize can still be used effectively when most/all users are anonymous. If you track users as visitors using a cookie or local storage, then a visitor's session ID can be considered the userId in Personalize. You will lose the continuity of stitching together the same logical user's activity across multiple sessions but you can still get in-session personalization. This requires calling PutEvents with the visitor's session ID in the sessionId field and excluding the userId field. Then when calling the GetRecommendations or GetPersonalizedRanking APIs, use the visitor's session ID as the userId field. Personalize will consider the event activity for the visitor's session when providing recommendations or reranking items.
If the visitor is a known user or later becomes known (i.e. signs in or creates an account), then pass their user ID in the userId field for PutEvents and GetRecommendations/GetPersonalizedRanking. At the next training, Personalize will associate any prior anonymous events (i.e. those with a sessionId but not a userId) to the user. The key is using a consistent sessionId across the anonymous and known events for the user for the session.

Event Sourcing - Data supplied to Command and data saved in Events

I am looking into event sourcing and I have a few thoughts that I need to get my head round.
Take for example an online shop -
The customer adds an item to the basket and saves their order.
The command handler could create an order on the customer aggregate root and add an OrderCreated event which contained the customer id, order id, item id, quantity and unit price. All pretty straight forward but what if the aggregate needed to check to see if that item was on special offer?
If this was for example a basket service would it subscribe to events from the catalog service and store it's own projections of the catalog service which it could then use, so then the basket service would comprise an event store and also some form of projection of the catalog service?
Or if in the example I've just described, if the basket and catalog functionality were part of the same application and they only held event data, then when a customer creates an order the handler would pull all ordered items from the event store via a repository, apply all events to them and then return them to the handler in order to check if the item was on special offer.
what if the aggregate needed to check to see if that item was on special offer?
It needs to execute a query to get the information it needs.
From the aggregate point of view those data are external, so it (or the handler sending the command to it) needs a query to access that information.
How the query work is up to you (there are pros and cons for each way), the query handler can:
Call a repository that loads an aggregate and check for the special offer (you can also think to have event sourcing in just one part of your system and having this part using another way to store dara, or not)
Make a remote call to the Catalog Service API to check for the special offer
Do a query to a local db, that is populated reading events emitted by the catalog service and stored "locally" to the basket service

Microstrategy - How to apply a security filter just to certain report?

I need to apply a filter in some report for some users.
I was told that the best way to do this is a security filter but i discovered that security filters are applied to all the reports that the user open.
I need some kind o filter that filter an attribute on a user but just on some reports, not all.
example:
if report1{
if user1 then attribute = 1
if user2 then attribute = 2
}
let's say i have departments and chiefs of those departments.
It is not a matter of security but a matter of comfort.
I want to avoid the chief of a department to manually select (prompt) his department.
It would be more comfortable if the system would recognize the user and show the data of his interest.
There a different ways to solve this kind of scenario, depending on the level of flexibility you want to offer to your user and the effort you need to implement and maintain the solution.
The User Login way
No flexibility, low maintenance, more effort to implement
Use the User Login prompt. This is a system prompt (created by default MicroStrategy) that returns the user login. If you have a table with the data that a user can see like this:
UserLogin YourAttribute
user1 attribute1
user2 attribute2
user3 attribute3
... ...
You can create an attribute UserLogin to be parent of the Attribute you want to use as filter and then create a filter (User Login = User Login System prompt)that you will put in your report.
More detailed information can be found here.
Once implemented this solution will you need to maintain that new table and when the user run a report with that filter it will be able to see only his data. It's similar to a security filter, but now you can decide where to apply the filter.
Multiple reports for multiple prompt defaults
Flexibility, high maintenance, little effort to implement
For each user create a copy of that report with the proper answer as default.
Maybe you can create ten reports now, but if you need to modify that report tomorrow you will need to modify ten report or recreate again all copies with different prompt answers.
Anyway this is good for the users, because they can change the prompt answers if they need.
Using URL to answer prompts
Flexibility, low maintenance, variable effort to implement
Instead to run the report using MicroStrategy you can provide to each user a specific URL that, using MicroStrategy URLAPI, answer automatically the prompt.
Of course you need to prepare the URLs in advance or find a way to do it programmatically. This is a good solution if the user don't want to navigate the MicroStrategy web interface but just run the report.
Subscribe the prompt answers
Flexibility, low maintenance, medium effort to implement
Have the report with the proper prompt answer delivered to your user every morning (or when you want). Using MicroStrategy Distribution Services you can deliver a report or document to your user and for each user you can specify the correct prompt answers.
No user can receive the full report in their mail box or just a link to their history link, opening that link they will see the report with their data. Of course users (or probably you) will need to setup all the subscriptions required.
Final thoughts
In these case I prefer to leave flexibility to users and teach them how to use the product. Of course there are some people they have no time for this kind of things (usually C something levels), in that case the best this is to have the data delivered to their email.
I understand some of these options are not that straight forward to implement if you are new to MicroStrategy.
My suggestion: for now go with the subscriptions (if you can) or teach your users how to save their own copy of that report (in My Reports) with the prompt already answered (oh, yes, this was another option, but each user has to do it), every time they will open it now, the prompt won't show up (but if you change the original report they will need to do it again).
Let me know if you need more details.

RESTful API - validation of related records

I implementing RESTful API service and i have a question about saving related records.
For example i have users table and related user_emails table. User emails should be unique.
On client side i have a form with user data fields and a number of user_email fields (user can add any number of fields independently). When the user saves the form i must first make query to create record in users table to get her ID, ​​and only then i can make query to save user emails (because in now i have id of record which come with response after saving user data). But if user enters not unique email in any field then the request will fail. So I create a record in the users table but not create record in user_emails table.
What are the approaches to implement validation of all this data before saving?
This is nor related restful api but transactional processing on the backend. If you are using Java, with JPA you can persist both element in the same transaction then you can notice if there is a problem and rollback the entire transaction returning a response.
I would condense it down to a single request, if you could. Just for performance's sake, if nothing else. Use the user_email as your key, and have the request return some sort of status result: if the user_email is unique, it'll respond with a success message. Otherwise, it'd indicate failure.
It's much better to implement that check solely on the server side and not both with the ID value unless you need to. It'll offer better performance to do that, and it'll let you change your implementation later more easily.
As for the actual code you use, since I'm not one hundred percent on what you're actually asking, you could use a MERGE if you're using SQL Server. That'd make it a bit easier to import the user's email and let the database worry about duplicates.

Why can't I trust a client-generated GUID? Does treating the PK as a composite of client-GUID and a server-GUID solve anything?

I'm building off of a previous discussion I had with Jon Skeet.
The gist of my scenario is as follows:
Client application has the ability to create new 'PlaylistItem' objects which need to be persisted in a database.
Use case requires the PlaylistItem to be created in such a way that the client does not have to wait on a response from the server before displaying the PlaylistItem.
Client generates a UUID for PlaylistItem, shows the PlaylistItem in the client and then issue a save command to the server.
At this point, I understand that it would be bad practice to use the UUID generated by the client as the object's PK in my database. The reason for this is that a malicious user could modify the generated UUID and force PK collisions on my DB.
To mitigate any damages which would be incurred from forcing a PK collision on PlaylistItem, I chose to define the PK as a composite of two IDs - the client-generated UUID and a server-generated GUID. The server-generated GUID is the PlaylistItem's Playlist's ID.
Now, I have been using this solution for a while, but I don't understand why/believe my solution is any better than simply trusting the client ID. If the user is able to force a PK collison with another user's PlaylistItem objects then I think I should assume they could also provide that user's PlaylistId. They could still force collisons.
So... yeah. What's the proper way of doing something like this? Allow the client to create a UUID, server gives a thumbs up/down when successfully saved. If a collision is found, revert the client changes and notify of collison detected?
You can trust a client generated UUID or similar global unique identifier on the server. Just do it sensibly.
Most of your tables/collections will also hold a userId or be able to associate themselves with a userId through a FK.
If you're doing an insert and a malicious user uses an existing key then the insert will fail because the record/document already exists.
If you're doing an update then you should validate that the logged in user owns that record or is authorized (e.g. admin user) to update it. If pure ownership is being enforced (i.e. no admin user scenario) then your where clause in locating the record/document would include both the Id and the userId. Now technically the userId is redundant in the where clause because the Id will uniquely find one record/document. However adding the userId makes sure the record belongs to the user that's doing the update and not the malicious user.
I'm assuming that there's an encrypted token or session of some sort that the server is decrypting to ascertain the userId and that this is not supplied by the client otherwise that's obviously not safe.
A nice solution would be the following: To quote Sam Newman's "Building Microservices":
The calling system would POST a BatchRequest, perhaps passing in a
location where a file can be placed with all the data. The Customer
service would return a HTTP 202 response code, indicating that the
request was accepted, but has not yet been processed. The calling
system could then poll the resource waiting until it retrieves a 201
Created indicating that the request has been fulfilled
So in your case, you could POST to server but immediately get a response like "I will save the PlaylistItem and I promise its Id will be this one". Client (and user) can then continue while the server (maybe not even the API, but some background processor that got a message from the API) takes its time to process, validate and do other, possibly heavy logic until it saves the entity. As previously stated, API can provide a GET endpoint for the status of that request, and the client can poll it and act accordingly in case of an error.

Resources