How can I configure Mass Transit Courier using Bus.Factory.CreateUsingRabbitMq? - masstransit

I am using Mass Transit Version 7 and I am facing a problem and I should note that I am a beginner in Mass Transit, so excuse me for my simple question.
My Question is How to Configure Mass Transit Courier using Bus.Factory.CreateUsingRabbitMq.

To configure activities without using a container, use the specific methods for compensate and execute activity hosts. There are different overloads if you need to specify an activity factory method or other configure the endpoint.
Bus.Factory.CreateUsingRabbitMq(cfg =>
{
cfg.Host(...);
Uri compensateAddress = default;
cfg.ReceiveEndpoint("activity-compensate", x =>
{
x.CompensateActivityHost<TActivity, TLog>();
compensateAddress = x.InputAddress;
});
cfg.ReceiveEndpoint("activity-execute", x =>
{
x.ExecuteActivityHost<TActivity, TArguments>(compensateAddress);
});
});

Related

Creating new 'belongs-to' relation in Laravel with form requests

I am new to Laravel and can't quite wrap my head around the Form Requests and how to use them. In simple cases, it's simple enough but what I need is a conditional creation of a related model before progressing with the rest of the request. Let me explain.
//Job model
job_id PK
client_id
some_field
//Client model
client_id
external_id
name
Now in my Create Job interface, I have a Select2 combo box that uses AJAX to search 2 different sources and can produce 3 different results.
So, say I am creating new Job and can have a POST looking like any of these:
Script found a Client with id 21, we just want to save, it all is simple
'client_id' => 21
'some_filed' => Whatever
OR
Script didn't find a Client but we did a search of external API and returned this Identifier, which I can then parse to create a new Client. This needs to be done before I save Job as I need to have a client_id ready for it
'client_id' => '196c3c7e34cde1d4593391ddf1901fd7'
'some_filed' => Whatever
OR
Script finds neither local Client nor a remote datapoint so we want to create a new Client using just the name provided. Of course this has to happen before saving the Job
'client_id' => 'My new client name'
'some_filed' => Whatever
Where do I perform all this functionality?
My first procedural guess would be to stick $data['client_id'] = Client::HandleClientAndReturnId($data['client_id']) in StoreJob's validationData() before returning the result.
But how would I handle/report possible validation issues with creating new Client and how to manage transaction - I don't want to create a Client if validation of Job fails.
I am using Form Requests and actually am parsing several models in the request already, but those are HAS_ONE type of relationships so I create them after the Job. Here I need to reverse the process. Here is what I have in my controller, if that is of any use:
class JobController extends Controller
{
public function store(StoreJob $request, StoreJobDataAdd $request_2, StoreJobDataSup $request_3)
{
$job = Job::create($request->validated());
if ($_POST['add_on']) {
$job->dataAdd()->create($request_2->validated());
}
if ($_POST['sup_on']) {
$job->dataSup()->create($request_3->validated());
}
return new JsonResponse([
'success' => true,
'message' => __('New Job has been created.')
]);
}
}
Here are my relations:
class Job extends Model
{
public function dataAdd()
{
return $this->hasOne(JobDataAdd::class, 'job_id', 'job_id');
}
public function dataSup()
{
return $this->hasOne(JobDataSup::class, 'job_id', 'job_id');
}
public function client()
{
return $this->belongsTo(Client::class, 'contact_id', 'contact_id_client');
}
}
I have a feeling I am missing the right way to do it but not quite sure where to look for the answers so please point me in the right direction.
Clarification:
The objective of the whole exercise is to allow users to create new Clients or select existing by using one combobox. It's a Select2 box. For unfamiliar - a dropdown replacement that has an ability to free-type a string that is used to search for existing records and if not found it sends to the server what user typed in. Something like a dynamic dropdown with ability to search and add options by the user.

One Bot App to support many Facebook pages [duplicate]

I love the bot framework, but I want to scale to support hundreds if not thousands of Facebook pages all pointing to my single bot instance. My bot instance differentiates functionality by the incoming page id, or I guess by the MSFT App/Secret IDs.
The framework appears to require a 1:1 correspondence between logical bot hosted by MSFT and a FB page, but my single bot instance can handle thousands of such pages and apps.
It looks like I might need to create a unique ChatConnector and associated UniversalBot instance for every logical bot-page. This is horribly inefficient at the scale I'm suggesting.
One way to solve this might be to extend UniversalBot to accept a list of all MSFT App and Secret IDs that I create, but I haven't tried this yet. After reviewing the API, looks like it might be possible to register more connectors with a single UniversalBot instance.
UniversalBot:
/**
* Registers or returns a connector for a specific channel.
* #param channelId Unique ID of the channel. Use a channelId of '*' to reference the default connector.
* #param connector (Optional) connector to register. If ommited the connector for __channelId__ will be returned.
*/
connector(channelId: string, connector?: IConnector): IConnector;
But not sure what I pass for channelId unless that's an arbitrary unique local value.
I have reviewed other/similar posts here, but not found specifically anything that I believe addresses my issue. If I'm mistaken I apologize and would appreciate a reference.
I am hoping someone might have a better idea. I am using Node btw. Thanks.
Taken from here:
Creating a Single Bot Service to Support Multiple Bot Applications
var express = require('express');
var builder = require('botbuilder');
var port = process.env.PORT || 3978;
var app = express();
// a list of client ids, with their corresponding
// appids and passwords from the bot developer portal.
// get this from the configuration, a remote API, etc.
var customersBots = [
{ cid: 'cid1', appid: '', passwd: '' },
{ cid: 'cid2', appid: '', passwd: '' },
{ cid: 'cid3', appid: '', passwd: '' },
];
// expose a designated Messaging Endpoint for each of the customers
customersBots.forEach(cust => {
// create a connector and bot instances for
// this customer using its appId and password
var connector = new builder.ChatConnector({
appId: cust.appid,
appPassword: cust.passwd
});
var bot = new builder.UniversalBot(connector);
// bing bot dialogs for each customer bot instance
bindDialogsToBot(bot, cust.cid);
// bind connector for each customer on it's dedicated Messaging Endpoint.
// bot framework entry should use the customer id as part of the
// endpoint url to map to the right bot instance
app.post(`/api/${cust.cid}/messages`, connector.listen());
});
// this is where you implement all of your dialogs
// and add them on the bot instance
function bindDialogsToBot (bot, cid) {
bot.dialog('/', [
session => {
session.send(`Hello... I'm a bot for customer id: '${cid}'`);
}
]);
}
// start listening for incoming requests
app.listen(port, () => {
console.log(`listening on port ${port}`);
});
We are creating different bot and connector instances that capture the App ID and password for each customer, and binding it to the corresponding REST API that is used by the Bot Framework as the Messaging Endpoint.
When we create the bot instance, we call the bindDialogsToBot method, passing the bot instance and the customer ID. By doing that, we capture the customer ID in its closure making it accessible to the internal dialogs.
When a call is made to one of the REST APIs, the relevant bot instance is used, and the correct customer ID can be utilized by the dialog’s internal logic to process the request (for example, to retrieve a customer’s configuration/rules and act upon them).

How to set dynamic SMTP data in Laravel 5.4 for queued emails?

In my application each user can use his own SMTP server. Therefor the config must be provided. I'm using Laravel Notifications to send the emails. If I'm using no queue (that means sync), there is no problem.
I made a CustomNotifiable Trait:
config([
'mail.host' => $setting->smtp_host,
'mail.port' => $setting->smtp_port,
'mail.username' => $setting->smtp_username,
'mail.password' => $setting->smtp_password,
'mail.encryption' => $setting->smtp_encryption,
'mail.from.address' => $setting->smtp_from_address,
'mail.from.name' => $setting->smtp_from_name,
]);
(new \Illuminate\Mail\MailServiceProvider(app()))->register();
After that, I restore the original config:
config([
'mail' => $originalMailConfig
]);
(new \Illuminate\Mail\MailServiceProvider(app()))->register();
No problem until now.
But if it's queued, just the first config after starting the queue worker will be taken for all further emails, even if any other SMTP config is provided. The default config from config/mail.php will be overridden. But this only works the first time.
I've made in the AppServiceProvider::boot method (the SMTP config is stored at the notification):
Queue::before(function (JobProcessing $event) {
// Handle queued notifications before they get executed
if (isset($event->job->payload()['data']['command']))
{
$payload = $event->job->payload();
$command = unserialize($payload['data']['command']);
// setting dynamic SMTP data if required
if (isset($command->notification->setting))
{
config([
'mail.host' => $command->notification->setting->smtp_host,
'mail.port' => $command->notification->setting->smtp_port,
'mail.username' => $command->notification->setting->smtp_username,
'mail.password' => $command->notification->setting->smtp_password,
'mail.encryption' => $command->notification->setting->smtp_encryption,
'mail.from.address' => $command->notification->setting->smtp_from_address,
'mail.from.name' => $command->notification->setting->smtp_from_name,
]);
(new \Illuminate\Mail\MailServiceProvider(app()))->register();
}
}
});
Of course, the original config get restored:
Queue::after(function (JobProcessed $event) use ($originalMailConfig) {
$payload = $event->job->payload();
$command = unserialize($payload['data']['command']);
// restore global mail settings
if (isset($command->notification->setting))
{
config([
'mail' => $originalMailConfig
]);
(new \Illuminate\Mail\MailServiceProvider(app()))->register();
}
});
It seems, as the Swift Mailer has a cache or something like that. I registered a new MailServiceProvider, which should simply replace the old one. So if I set the config with the new SMTP data, the new registered provider should take them. Logging the config shows even in the TransportManager, that the correct SMTP data were set, right before sending the mail, but the mail was sent with the first set config.
I found this thread and tried the linked solution, but with the same result: How to set dynamic SMTP details laravel
So I need a way to override the Services / ServiceProvider / SMTP config. Even if the Supervisor restarts the queue, there is a chance that multiple emails with different configs should be send at the same time.
In Laravel 5.4+, as I see that the Mailer Class is a singleton that hold a MailTransport Class, which is responsible for the config of SMTP mail and is a singleton,too; I just have to override the config using the following approach:
First, I setup a trait so I can just turn this feature on some Mails:
trait MailSenderChangeable
{
/**
* #param array $settings
*/
public function changeMailSender($settings)
{
$mailTransport = app()->make('mailer')->getSwiftMailer()->getTransport();
if ($mailTransport instanceof \Swift_SmtpTransport) {
/** #var \Swift_SmtpTransport $mailTransport */
$mailTransport->setUsername($settings['email']);
$mailTransport->setPassword($settings['password']);
}
}
}
Then, in the build() method of your mail class, you can utilize the above trait and call:
$this->changeMailSender([
'email'=>$this->company->email,
'password'=>$this->company->email_password,
]);
Boom, let the Laravel do the rest.
After a lot of researching I stumbled upon the different queue commands. I tried queue:listen (which is not described in the Laravel 5.4 docs) instead of queue:work and the problems are gone.
Of course, this doesn't really explain the described behavior, but fortunately it doesn't matter, because I can live with this solution/workaround.
Another strange behavior is, that from time to time the queue worker throws an exception because the database was locked. No idea, when or why this happened.
This post explained a little bit, why things can happen: What is the difference between queue:work --daemon and queue:listen
In a nutshell, queue:listen solved my problem and another very strange db lock problem as well.

How to enable route tracing programmatically in Angular 2?

I know I can enableTracing on the Angular 2 router:
export const routing: ModuleWithProviders =
RouterModule.forRoot(routes, { enableTracing: true });
Is there any way to programatically set that value?
I have a config.json file that has a number of application settings. I would like to include a boolean property that can be used to control whether tracing is on or not. I'd rather not have the customer have the ability to modify the file that contains my routes, but still have the ability to turn on tracing to help debug edge cases that didn't get caught by tests.
I'm OK with having to restart the application, but not OK with having to rebuild.
[Update]
After looking at the router source, it doesn't look do-able without a pull request. Simple explanation of what the change would need to be:
In router.ts, add a public property called tracing: boolean
In router_module.ts::setupRouter:
Change
if (opts.enableTracing) {
to
router.tracing = opts.enableTracing</pre>
Change the observable:
router.events.subscribe(e => { ...
to
router.events
.filter(e => router.tracing)
.subscribe(e => { ...</li>
3. Probably need to add some validation on the tracing property.
With these changes, one could import Router and then set the router.tracing property to turn it on and off.
I have no idea what the performance difference is between emitting all of the events with no subscriber and emitting all of the events with a filtered subscription.
For now there is no explicit way to do it programmatically. Our workaround is to enable it only for local development so that we can get all the details/exception-stacktrace etc. Something like:
let routes = [{path: ..., component : ...}, ...];
RouterModule.forRoot(routes, {
enableTracing: /localhost/.test(document.location.host)
});

Using custom WP-API endpoints with the included Backbone JS client library

So I have created a custom endpoint using WP-API plugin. When testing with Postman, the endpoint works as expected.
The problem is that when I try to access the custom enpoint using the built in Backbone JS client, I cannot see my new endpoints in the wp.api.models object.
I have been digging and I think I have to send initialise it with a different schema or something, but have aboslutely no idea how to and can't find any info on how to extend wp.api.models so I can access my custom methods.
Example plugin code:
function my_awesome_func( $data ) {
return 'A STRING';
}
function initrest() {
register_rest_route( 'wp/v2', '/score', array(
'methods' => 'GET',
'callback' => 'my_awesome_func',
));
}
add_action( 'rest_api_init', 'initrest');
Example template code:
window.onload = function() {
console.log(wp.api.models);
};
This ouputs a list of the common models for Post, Comment, Tags etc, but no sign of my 'scores' endpoint.
Try initializing the wp api with your own route.
wp.api.init({'versionString' : 'custom-route/v1/', 'apiRoot': 'http://my-website.com/wp-json/'}).done(function()
{
console.log(wp.api.models);
});
Whereas versionString and apiRoot need to be replaced with your own data.
I'm afraid custom endpoints don't make into the wp.api.models by design of the Backbone client. Have a look to my question and the respective answers. They boil down to: "use a different client".
I use node-wpapi.

Resources