Rebus Message Mutator - rebus

At one point Rebus supported Message Mutators. I can't seem to find them anymore in the Rebus source code. Were they renamed? Do they still exist?
Sample code:
Configure.With(senderAdapter)
.Transport(t => t.UseMsmq(SenderInputQueueName, "error"))
.Events(e =>
{
e.MessageMutators.Add(new EvilMutator("first"));
e.MessageMutators.Add(new EvilMutator("second"));
e.MessageMutators.Add(new EvilMutator("third"));
})
.CreateBus().Start();

"Rebus 2" (all versions of Rebus since 0.90.0) does not have message mutators, because it's super extensible, and adding something that mutates an incoming/outgoing message is pretty easy with the incoming/outgoing pipelines.
The pipelines follow the "Russian doll" model where each step is responsible for calling the rest of the pipeline.
Adding a new "mutator" step can be done like this – first, we create a step that is capable of mutating incoming/outgoing messages:
public class MyMutatorStep : IIncomingStep, IOutgoingStep
{
public async Task Process(OutgoingStepContext context, Func<Task> next)
{
// here we have the message
var message = context.Load<Message>();
// mutate (or, more like "cripple", actually πŸ˜‰)
context.Save(new Message(headers: message.Headers, body: new object()));
await next();
}
public async Task Process(IncomingStepContext context, Func<Task> next)
{
// here we have the message again
var message = context.Load<Message>();
await next();
}
}
and then we decorate the pipeline, injecting the step before serialization/after deserialization respectively:
Configure.With(...)
.(...)
.Options(o => o.Decorate<IPipeline>(c => {
var pipeline = c.Get<IPipeline>();
var step = new MyMutatorStep();
return new PipelineStepInjector(pipeline)
.OnReceive(step, PipelineStepRelativePosition.After, typeof(DeserializeIncomingMessageStep))
.OnSend(step, PipelineStepRelativePosition.Before, typeof(SerializeOutgoingMessageStep));
}))
.Start();
In this example, I mutate the outgoing message by replacing the message body with new object(), which is probably not what you want πŸ˜‰ but hopefully, you can get an idea of the possibilities.

Related

Next JS pages/api; having trouble calling influxdb client from api

I have written a handler function inside my nextjs page/api folder;
handler(req, res) {}
Am using #influxdata/influxDb-client as mentioned in the documentation. Am using
from(queryAPI.rows(query).pipe(....).subscribe(next(value)=> {results.push(value}, complete(console.log(results); res.status(200).json(results)}
Am getting all the query value, once the observable is completed. it works most of the time.
Am pushing the intermediate results in the next part of the subscriber and trying to send the results back to client in the complete part of the subscriber. I want the request handler to wait till i get all my values from influx DB query in the complete part of the subscriber and can send the value back to client..
But the issue "Handler function will not Wait till the observable is completed". Handler function returns, before the observer gets completed. Am getting error: API resolved without sending a response...
I get all the values only when the observer is completed.
I don't know how to handle the scenario.
How can I make the handler function wait until the observable is completed?
I found the solution for the same
I used new Promise() with await, added my observable inside this promise and resolved the promise on Complete of the subscribe.
Code will look like the following :
export async function handler (req, res) {
const results=[];
await new Promise((resolve, reject) => {
from((queryAPIs.rows(query))
.pipe(map(({values, tableMeta}) => tableMeta.toObject(values)))
.subscribe(
{
next(object) => {results.push(object)}
complete() => { resolve (results) }
error(err) => { reject (err) }
});
res.status(200).send(results);
}
}

Firebase cloud function error: Maximum call size stack size exceeded

I've made firebase cloud function which adds the claim to a user that he or she has paid (set paid to true for user):
const admin = require("firebase-admin");
exports.addPaidClaim = functions.https.onCall(async (data, context) => {
// add custom claim (paid)
return admin.auth().setCustomUserClaims(data.uid, {
paid: true,
}).then(() => {
return {
message: `Succes! ${data.email} has paid for the course`,
};
}).catch((err) => {
return err;
});
});
However, when I'm running this function: I'm receiving the following error: "Unhandled Rejection (RangeError): Maximum call stack size exceeded". I really don't understand why this is happening. Does somebody see what could cause what's getting recalled which in turn causes the function to never end?
Asynchronous operations need to return a promise as stated in the documentation. Therefore, Cloud Functions is trying to serialize the data contained by promise returned by transaction, then send it in JSON format to the client. I believe your setCustomClaims does not send any object to consider it as an answer to the promise to finish the process so it keeps in a waiting loop that throws the Range Error.
To avoid this error I can think of two different options:
Add a paid parameter to be able to send a JSON response (and remove the setCustomUserClaim if it there isn’t any need to change the user access control because they are not designed to store additional data) .
Insert a promise that resolves and sends any needed information to the client. Something like:
return new Promise(function(resolve, reject) {
request({
url: URL,
method: "POST",
json: true,
body: queryJSON //A json variable I've built previously
}, function (error, response, body) {
if (error) {
reject(error);
}
else {
resolve(body)
}
});
});

rxjs - How to retry after catching and processing an error with emitting something

I'm using rxjs v5.4.3, redux-observable v0.16.0.
in my application, I'd like to achieve below:
an user has auth token, and refresh token to regenerate auth token.
the user requests with auth token. (by emitting REQUEST action)
if it failed, request regenerating auth token with refresh token.
if refreshed, emit TOKEN_REFRESHED action to update auth token, and do not emit REQUEST_FAILURE.
if refreshing failed, emit REQUEST_FAILURE
after refreshing(and updating auth token reducer), retry requesting using the refreshed auth token.
if request succeeded, emit REQUEST_SUCCESS, and if failed, emit REQUEST_FAILURE.
I'd like to achieve like:
const fetchEpic = (action$: ActionsObservable<Action>, store: Store<IRootState>) => action$
.ofAction(actions.fetchPost)
.mergeMap(({ payload: { postId } })) => {
const { authToken, refreshToken } = store.getState().auth;
return api.fetchPost({ postId, authToken }) // this returns Observable<ResponseJSON>
.map(res => actions.fetchSuccess({ res })) // if success, just emit success-action with the response
.catch(err => {
if (isAuthTokenExpiredError(err) {
return api.reAuthenticate({ refreshToken })
.map(res => actions.refreshTokenSuccess({ authToken: res.authToken });
.catch(actions.fetchFailure({ err }))
// and retry fetchPost after re-authenticate!
}
return Observable.of(actions.fetchFailure({ err }))
})
}
is there any solution?
There are many ways to do it, but I would recommend splitting off the reauthentication into its own epic to make it easier to maintain/test/reuse.
Here's what that might look like:
const reAuthenticateEpic = (action$, store) =>
action$.ofType(actions.reAuthenticate)
.switchMap(() => {
const { refreshToken } = store.getState().auth;
return api.reAuthenticate({ refreshToken })
.map(res => actions.refreshTokenSuccess({ authToken: res.authToken }))
.catch(err => Observable.of(
actions.refreshTokenFailure({ err })
));
});
We'll also want to use something like Observable.defer so that each time we retry, we look up the latest version of the authToken:
Observable.defer(() => {
const { authToken } = store.getState().auth;
return api.fetchPost({ postId, authToken });
})
When we catch errors in fetchEpic and detect isAuthTokenExpiredError we return an Observable chain that:
Starts listening for a single refreshTokenSuccess, signalling we can retry
Just in case the reauthing itself fails, we listen for it with .takeUntil(action$.ofType(refreshTokenFailure)) so that we aren't waiting around forever--you might want to handle this case differently, your call.
mergeMap it to the original source, which is the second argument of the catch callback. The "source" is the Observable chain before the catch, and since Observables are lazy, when we receive the refreshTokenSuccess action it it will resubscribe to that chain again, effectively be a "retrying"
Merge the above chain with an Observable of an reAuthenticate action. This is used to kick off the actual reauth.
To summarize: the Observable chain we return from catch will first starting listening for refreshTokenSuccess, then it emits reAuthenticate, then when (and if) we receive refreshTokenSuccess we will then "retry" the source, our api.fetchPost() chain above the catch that we wrapped in an Observable.defer. If refreshTokenFailure is emitted before we receive our refreshTokenSuccess, we give up entirely.
const fetchEpic = (action$, store) =>
action$.ofType(actions.fetchPost)
.mergeMap(({ payload: { postId } })) =>
Observable.defer(() => {
const { authToken } = store.getState().auth;
return api.fetchPost({ postId, authToken });
})
.map(res => actions.fetchSuccess({ res }))
.catch((err, source) => {
if (isAuthTokenExpiredError(err)) {
// Start listening for refreshTokenSuccess, then kick off the reauth
return action$.ofType(actions.refreshTokenSuccess)
.takeUntil(action$.ofType(refreshTokenFailure))
.take(1)
.mergeMapTo(source) // same as .mergeMap(() => source)
.merge(
Observable.of(action.reAuthenticate())
);
} else {
return Observable.of(actions.fetchFailure({ err }));
}
});
);
These examples are untested, so I may have some minor issues but you hopefully get the gist. There's also probably a more elegant way to do this, but this will at least unblock you. (Others are more than welcome to edit this answer if they can decrease the complexity)
Side notes
This creates the slight potential for infinite retries, which can cause nasty issues both in the person's browser or your servers. It might be a good idea to only retry a set number of times, and/or put some sort of delay in between your retries. In practice this might not be worth worrying about, you'll know best.
You (or someone else reading this later) may be tempted to use .startWith(action.reAuthenticate()) instead of the merge, but be mindful that a startWith is just shorthand for a concat, not a merge, which means it would synchronously emit the action before we have started to listen for a success one. Usually that isn't an issue since http requests are async, but it's caused people bugs before.

How to handle loss of connection in Angular2 with RXJS HTTP when polling

I have the following code (simplified for this post) - assume an initial call to onStart().
Running this works fine. If I lose the internet connection I get the net::ERR_INTERNET_DISCONNECTED error (as expected) but the polling stops.
Clearly I am not handling any errors here as that is where I'm getting stuck. I'm not clear where I handle those errors and how? Do I need to call startPolling() again?
I need the polling to continue even if there is no internet connection, so that on re-connection data is updated. Any advice please?
onStart() {
this.startPolling().subscribe(data => {
// do something with the data
});
}
startPolling(): Observable<any> {
return Observable
.interval(10000)
.flatMap(() => this.getData());
}
getData() {
var url = `http://someurl.com/api`;
return this.http.get(url)
.map(response => {
return response.json();
});
}
Thanks in advance.
If you know the error happens because of this.http.get(url) then you can add catch() operator that lets you subscribe to another Observable instead of the source Observable that sent an error notification.
getData() {
var url = `http://someurl.com/api`;
return this.http.get(url)
.catch(err => Observable.empty())
.map(response => {
return response.json();
});
}
This will simply ignore the error and won't emit anything.

HTTP GET and POST, how to implement in Angular 2 to be able to list, add and remove objects

Okay, so I am new to working with HTTP and actually getting some data from the server. Been sifting through a lot of tutorials, examples and questions asked here, but I am not finding what I want. All tutorials I've found only shows how to retrieve and add some data.
So based on those examples I've managed to retrieve data:
service:
getCases(){
return this.http.get('someUrl');
}
Case component constructor:
this._service.getCases()
.map((res: Response) => res.json())
.subscribe(cases => this.cases = cases);
Adding cases
service:
public saveCase(case: case) {
let body = JSON.stringify(case);
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
return this.http.post('someUrl', body, options)
.map(this.extractData)
.catch(this.handleError)
.subscribe(case => this.cases.push(case));
}
Case Component:
saveCase() {
let case = new Case(this.id, this.name, this.date)
this._service.saveCase(case);
this.name = '';
}
Okay, so I have and Array "Cases" which contains Case objects. Getting the data from the server displays the cases like I want them to. When I add a new case it gets sent to the server, but how do I get the Array updated when I add a new Case. Because now the new case appears only after I refresh the browser.
Second question is that the user can click a case and it then routes to a detail list where the user can add steps and feedback. If it matters, case has the attributes id, name, date and an array of steps, at this point the array is empty. The step object is it's own class and the object contains an array of feedback. Feedback is also an own class and the object has two attributes, which are both strings. So it's all nested. When I click the case, it does route to the detail page, but there the case name should be printed and it doesn't. It also shows my button for adding steps, but it does nothing. Obviously I'm missing something in my methods, but I have no clue to as what to do. As a comment I can say that before adding the http in my code it all worked as it should. Here are the methods, that are probably missing something:
Case Component:
gotoDetail(case: Case) {
this._router.navigate(['CaseDetail', {"id": case.name}]);
}
Service:
public getById(id: string): Case {
for (let case of this.cases) {
if (case.id === id) {
return case;
}
}
return null;
}
Then there is the matter of syntax for removing cases, haven't found an example that works for me yet, I've tried a bunch... among others the example links provided by #shershen below. None works. The original methods I have, that should be changed to work with http:
Component:
removeSearchCase(case: Case) {
this._service.removeCase(case);
}
Service:
public removeCase(value: Case): void {
let index = this.cases.indexOf(value);
this.cases.splice(index, 1);
}
So the case removal is with post.
And about the backend I can say as much that I only have the following three posts and gets:
getCases (GET), saveCase (also works as updating the case)(POST) and removeCase (POST).
It's hard to debug without sample demo, however the descriptions quite detailed. I am adding some points that may fix the problem while improving the code structure:
First, you should move the request subscription/observing into the service methods; that will encapsulate the request handling logic in service layer:
//service.ts
#Injectable()
export class service {
getCases(){
if (!this.request) {
this.request = this.http.get('/assets/data.json')
.map((response: Response) => response.json())
.map((data: string[]) => {
this.request = null;
return this.names = data;
});
}
return this.request;
}
}
Second, you need to create an instance of your service in your Component's constructor instead of using it as a static method of the service:
//component.ts
import {MyService} from 'PATH_TO_YOUR_SERVICE';
class CaseComponent {
constructor(private _service : MyService){
//other stuff..
}
getData(){
this._service.getCases()
}
}
Additional references:
Official "Getting and Saving Data with HTTP"
Service example with Observables (with Firebase, but still)
Simple service in Angular2 seed project
I think you should put your cases Array in the CaseComponent:
case.component.ts:
cases: Case[];
constructor(private caseService: CaseService){}
getCases() {
this.caseService.getCases()
.subscribe(cases => this.cases = cases);
}
saveCase() {
let case = new Case(this.id, this.name, this.date);
this.caseService.saveCase(case)
.subscribe(case => this.cases = [...this.cases, case]);
}
case.service.ts:
getCases() {
return this.http.get(this.casesUrl)
.map(this.extractData)
.catch(this.handleError);
}
saveCase (case: Case) {
let body = JSON.stringify({ case });
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
return this.http.post(this.casesUrl, body, options)
.map(this.extractData)
.catch(this.handleError);
}
Then try to change "name" to "id" in gotoDetail:
gotoDetail(case: Case) {
this._router.navigate(['CaseDetail', {"id": case.id}]);
}

Resources