I am using ABP's PublishAsync method for publishing notifications, but in some cases (in production) it creates multiple notifications instead of one. Method isn't in any loop, but still it creates multiple records in AbpTenantNotifications table (in space of 0.1 sec). Method looks like this:
public async Task Publish_RegularNotification(NotificationDetails notificationDetails, UserIdentifier[] users)
{
notificationDetails = AttachAdditionalDataToNotification(notificationDetails);
await _notificationPublisher.PublishAsync(
notificationDetails.NotificationName,
notificationDetails,
severity: NotificationSeverity.Info,
userIds: users
);
}
Has anyone encountered this problem?
Related
I'm using rxjs with NodeJS in backend.
I have a Rest API which allow consumers to run remote yarn installation process. The install function returns an observable of the process. So when the module is installed successfully it emits a value in the observable and complete. At this point, the Rest API will returns a response to the user to say that the installation is successful. In case that the installation fails, the process will throw an Error in the stream and the Rest API returns another response with the error information.
My issue is:
The API is called multiple times in parallel by consumers, so there will be a parallel installations in the backend.
I tried throttle operator to create a queue but it keeps the first stream active. So if the first process is "completed", it returns "true" but the stream doesn't complete
export class MyService {
// the function called by the REST API
installGlobal(moduleName: string): Observable < boolean > {
// I think, there are something to do here to make it queuing
return this.run('yarn', ['global', 'add', moduleName]);
}
private run(cmd: string, args: string[]): Observable < boolean > {
const cmd$ = fromPromise(spawn(cmd, args)).pipe(
map(stdout => {
this.logger.info(`Install Module Successfully`);
this.logger.info(`stdout: ${stdout.toString()}`);
return true;
}),
catchError(error => {
const errorMessage: string = error.stderr.toString();
return _throw(errorMessage.substr(errorMessage.indexOf(' ') + 1));
})
);
return cmd$;
}
}
My expectation:
Either there are multiple request, they must be queued. So the first one will be treated and all parallel onces must be queued. When the first is processed, it must returns the response to the API consumers (like 200 completed) and resume the next stream from the queue.
[UPDATE-01 July 2019]: adding an example
You can fetch a demo of the code at stackblitz
I have reimplemented the existant code and i'm simulating my API call by subscribing multi time to the service which will call the queue
A simple queque in Rxjs can be done like below
const queque=new Subject()
// sequential processing
queue.pipe(concatMap(item=>yourObservableFunction(item)).subscribe()
// add stuff to the queue
queque.next(item)
What's the standard means of processing input to an AWS Lambda handler function, when the format of the incoming JSON varies depending on the type of trigger?
e.g. I have a Lambda function that gets called when an object is created in an S3 bucket, or when an hourly scheduled event fires. Obviously, the JSON passed to the handler is formatted differently.
Is it acceptable to overload Lambda handler functions, with the input type defined as S3Event for one signature and ScheduledEvent for the other? If not, are developers simply calling JsonConvert.DeserializeObject in try blocks? Or is the standard practice to establish multiple Lambda functions, one for each input type (yuck!)?
You should use one function per event.
Having multiple triggers for one Lambda will just make things way harder, as you'll end up with a bunch of if/else, switch statements or even Factory methods if you want to apply design patterns.
Now think of Lambda functions as small and maintainable. Think of pieces of code that should do one thing and should do it well. By the moment you start having multiple triggers, you kind of end up with a "Lambda Monolith", as it will have way too many responsibilities. Not only that, you strongly couple your Lambda functions with your events, meaning that once a new trigger is added, your Lambda code should change. This is just not scalable after two or three triggers.
Another drawback is that you are bound to using one language only if you architect it like that. For some use cases, Java may be the best option. But for others, it may be Node JS, Python, Go...
Essentially, your functions should be small enough to be easily maintainable and even rewritten if necessary. There's absolutely nothing wrong with creating one function per event, although, apparently, you strongly disapprove it. Think of every Lambda as a separate Microservice, which scales out independently, has its own CI/CD pipeline and its own suite of tests.
Another thing to consider is if you want to limit your Lambda concurrent executions depending on your trigger type. This would be unachievable via the "One-Lambda-Does-It-All" model.
Stick with one Lambda per trigger and you'll sleep better at night.
This is actually possible by doing the following:
Have the Lambda signature take a Stream rather than the Amazon event type, so we can get the raw JSON message.
Read the JSON contents of the stream as a string.
Deserialize the string to a custom type in order to identify the event source.
Use the event source information to deserialize the JSON a second time to the appropriate type for the event source.
For example:
public async Task FunctionHandler(Stream stream, ILambdaContext context)
{
using var streamReader = new StreamReader(stream);
var json = await streamReader.ReadToEndAsync();
var serializationOptions = new JsonSerializationOptions { PropertyNameCaseInsensitive = true };
var awsEvent = JsonSerializer.Deserialize<AwsEvent>(json, serializationOptions);
var eventSource = awsEvent?.Records.Select(e => e.EventSource).SingleOrDefault();
await (eventSource switch
{
"aws:s3" => HandleAsync(Deserialize<S3Event>(json, serializationOptions), context),
"aws:sqs" => HandleAsync(Deserialize<SQSEvent>(json, serializationOptions), context),
_ => throw new ArgumentOutOfRangeException(nameof (stream), $"Unsupported event source '{eventSource}'."),
});
}
public async Task HandlyAsync(S3Event #event) => ...
public async Task HandleAsync(SQSEvent #event) => ...
public sealed class AwsEvent
{
public List<Record> Records { get; set; }
public sealed class Record
{
public string EventSource { get; set; }
}
}
I have the following requirement.
I have An Angular service with an BehaviorSubject.
A http request is done and when this is done the BehaviorSubject.next method is invoked with the value.
This value can change during the lifecycle of the single page.
Different subscribers are registered to it and get invoked whenever this changes.
The problem is that while the http request is pending the BehaviorSubject already contains a default value and subscribers are already immediately getting this value.
What I would want is that subscribers have to wait till the http request is done (deferred) and get the value when the http request is done and sets the value.
So what I need is some kind of deferred Behavior subject mechanism.
How would i implement this using rxjs?
Another requirement is that if I subscribe to the behaviorsubject in a method we want the subcriber to get the first non default value and that the subscription ends. We don't want local subscriptions in functions to be re-executed.
Use a filter on your behavior subject so your subscribers won't get the first default emitted value:
mySubject$: BehaviorSubject<any> = new BehaviorSubject<any>(null);
httpResponse$: Observable<any> = this.mySubject$.pipe(
filter(response => response)
map(response => {
const modifyResponse = response;
// modify response
return modifyResponse;
}),
take(1)
);
this.httpResponse$.subscribe(response => console.log(response));
this.myHttpCall().subscribe(response => this.mySubject$.next(response));
You can of course wrap the httpResponse$ observable in a method if you need to.
I think the fact that you want to defer the emitted default value, straight away brings into question why you want to use a BehaviorSubject. Let's remember: the primary reason to use a BehaviorSubject (instead of a Subject, or a plain Observable), is to emit a value immediately to any subscriber.
If you need an Observable type where you need control of the producer (via .next([value])) and/or you want multicasting of subscription out of the box, then Subject is appropriate.
If an additional requirement on top of this is that subscribers need a value immediately then you need to consider BehaviorSubject.
If you didn't say you need to update the value from other non-http events/sources, then I would've suggested using a shareReplay(1) pattern. Nevertheless...
private cookieData$: Subject<RelevantDataType> = new
Subject<RelevantDataType>(null);
// Function for triggering http request to update
// internal Subject.
// Consumers of the Subject can potentially invoke this
// themselves if they receive 'null' or no value on subscribe to subject
public loadCookieData(): Observable<RelevantDataType> {
this.http.get('http://someurl.com/api/endpoint')
.map(mapDataToRelevantDataType());
}
// Function for dealing with updating the service's
// internal cookieData$ Subject from external
// consumer which need to update this value
// via non-http events
public setCookieData(data: any): void {
const newCookieValue = this.mapToRelevantDataType(data); // <-- If necessary
this.cookieData$.next(newCookieValue); // <-- updates val for all subscribers
}
get cookieData(): Observable<RelevantDataType> {
return this.cookieData$.asObservable();
}
The solution is based on OPs comments etc.
- deals with subscribing to subject type.
- deals with external subscribers not being able to 'next' a new value directly
- deals with external producers being able to set a new value on the Subject type
- deals with not giving a default value whilst http request is pending
I'm looking for some guidance on the correct way to setup a WebSocket connection with RxJS 5. I am connecting to a WebSocket that uses JSON-RPC 2.0. I want to be able to execute a function which sends a request to the WS and returns an Observable of the associated response from the server.
I set up my initial WebSocketSubject like so:
const ws = Rx.Observable.webSocket("<URL>")
From this observable, I have been able to send requests using ws.next(myRequest), and I have been able to see responses coming back through the ws` observable.
I have struggled with creating functions that will filter the ws responses to the correct response and then complete. These seem to complete the source subject, stopping all future ws requests.
My intended output is something like:
function makeRequest(msg) {
// 1. send the message
// 2. return an Observable of the response from the message, and complete
}
I tried the following:
function makeRequest(msg) {
const id = msg.id;
ws.next(msg);
return ws
.filter(f => f.id === id)
.take(1);
}
When I do that however, only the first request will work. Subsequent requests won't work, I believe because I am completing with take(1)?
Any thoughts on the appropriate architecture for this type of situation?
There appears to be either a bug or a deliberate design decision to close the WebSocket on unsubscribe if there are no further subscribers. If you are interested here is the relevant source.
Essentially you need to guarantee that there is always a subscriber otherwise the WebSocket will be closed down. You can do this in two ways.
Route A is the more semantic way, essentially you create a published version of the Observable part of the Subject which you have more fine grained control over.
const ws = Rx.Observable.webSocket("<URL>");
const ws$ = ws.publish();
//When ready to start receiving messages
const totem = ws$.connect();
function makeRequest(msg) {
const { id } = msg;
ws.next(msg);
return ws$.first(f => f.id === id)
}
//When finished
totem.unsubscribe();
Route B is to create a token subscription that simply holds the socket, but depending on the actual life cycle of your application you would do well to attach to some sort of closing event just to make sure it always gets closed down. i.e.
const ws = Rx.Observable.webSocket("<URL>");
const totem = ws.subscribe();
//Later when closing:
totem.unsubscribe();
As you can see both approaches are fairly similar, since they both create a subscription. B's primary disadvantage is that you create an empty subscription which will get pumped all the events only to throw them away. They only advantage of B is that you can refer to the Subject for emission and subscription using the same variable whereas A you must be careful that you are using ws$ for subscription.
If you were really so inclined you could refine Route A using the Subject creation function:
const safeWS = Rx.Subject.create(ws, ws$);
The above would allow you to use the same variable, but you would still be responsible for shutting down ws$ and transitively, the WebSocket, when you are done with it.
I'm just getting started with RXJS to see if it can replace my currently manual data streams. One thing I'm trying to port is a situation whereby the last value in the stream is remembered, so future observers will always get the 'current' value as well as subsequent ones. This seems to be fulfilled by BehaviorSubject.
However, I need to do this for a group of entities. For example, I might have data that represents a message from a user:
{ userId: 1, message: "Hello!" }
And I want a BehaviorSubject-like object that'll store the last message for all users. Is this something I can do with RXJS out-of-the-box, or would I need to do it myself? (If so, any pointers would be appreciated).
EDIT: After some more thought, it perhaps seems logical to having an 'incoming' subject, an observer that updates a Map, and then a function which I can call which initialises an Observable from the map values, and merges with the incoming stream...?
I use RxJS with a redux-like state setup. I have a BehaviorSubject that holds the current state, and every time an event/action is fired that current state gets passed through functions that produce a new state, which the subject is subscribed to.
Here's a simplified version of what I use:
export default class Flux {
constructor(state) {
//all resources are saved here for disposal (for example, when hot loading)
//this is just a flux dispatcher
this.dispatcher = new rx.Subject(),
// BehaviorSuject constructed with initial state
this.state = new Rx.BehaviorSubject(state),
}
addStore(store, initialState, feature = store.feature) {
this.dispatcher
.share()
// this is where the "reduction" happens. store is a reducer that
// takes an existing state and returns the new state
.flatMap(({action, payload}) =>
store(this.state.getValue(), action, payload))
.startWith(initialState || {})
.subscribe(this.state)
);
return this;
}
addActions(actions: rx.Subject) {
// actions are fed to the dispatcher
this.resources.push(actions.share().subscribe(this.dispatcher));
return this;
}
}
I create a global Flux object with manages state. Then, for every "feature" or "page" or whatever I wish I add actions and stores. It makes managing state very easy, and things like time-travel are something that are a given with Rx.