When calling WebMethod on a Webpage using jQuery. We define this as static.
However static methods always have one instance. What happens when multiple web requests are made.
Does it really happen asynchronously or
all the requests are pipelined waiting for the WebMethod to accept the requests?
I created a sample console program to simulate the scenario on static method work & found them to execute in sequential order.
class Program
{
static int count = 10;
static void Main(string[] args)
{
new Program().foobar();
Console.ReadLine();
}
public void foobar()
{
Parallel.Invoke(() => work("one"), () => work("two"), () => work("three"), ()=> work("four"));
}
static void work(string str)
{
Thread.Sleep(3000);
count++;
Console.WriteLine(str + " " + count);
}
}
Can you please put some light on this concept?
They will not execute sequentially. If you created multiple apps in a client server scenario it would be a better example since your console app inherently runs everything sequentially.
That said, with the static methods you just need to be aware of shared resources, data, etc. Local data is fine.
Related
I am building an integration test where I am using InMemNetwork to run the test.
There is a Thread.Sleep call just before an assert but that is a dodgy way of testing and it slows down our tests a lot.
I am also doing some integration tests using SagaFixtures and a simple IBus implementation that runs synchronously but its all a bit tedious with registering handlers, running handlers and deferring messages.
Is there a way to wait on all threads in use by Rebus until they are finished executing without augmenting production code using things like ManualResetEvent (used in Rebus own tests)?
I usually use SagaFixture as you do, and then I use FakeBus to inject into saga handlers in order to capture their actions.
Most of my tests are unit tests of simple handlers though, but I will often inject "real" service, like e.g. implementation of IThis and IThat that go to a real database.
For a couple of scenarios though I spin up multiple endpoints with an in-mem transport, and then I usually implement an extension on InMemNetwork that helps me wait for particular events to be published or something like that – it could look like this in a test:
var updated = await Network.WaitForNext<WhateverUpdated>(subscriberAddress, timeoutSeconds: 20);
where WaitForNext is simply an extension method that polls the queue specified by subscriberAddress for the next message and tries to deserialize it as WhateverUpdated.
I hope that can give you some inspiration :)
For some scenario's I use the following approach to wait for Rebus to complete all message processing. The rebus endpoints are hosted in separate exe's and the rebus filesystem transport is used for integration tests (normally it's Azure SB). The integration test spins up the exe's and in each exe Rebus is configured with 0 workers, so it's doing nothing. Then in the test we have a WaitForMessagesProcessed() method that configures a number of workers and blocks until there are no more messages to be processed.
Here is how it roughly looks in code:
public class MessageProcessor() {
private string queueName;
private int messagesWaitingForProcessing;
private IBus bus;
public MessageProcessor(string queueName) {
this.queueName = queueName;
this.bus = Configure.With(adapter)
.Transport(t => t.UseFileSystem(#"c:\baseDirectory", this.queueName))
.Options(o =>
{
o.SetNumberOfWorkers(0);
})
.Events(e =>
{
e.BeforeMessageSent += (thebus, headers, message, context) =>
{
// When sending to itself, the message is not queued on the network.
var m = context.Load<Rebus.Pipeline.Send.DestinationAddresses>();
if (m.Any(t => t == this.queueName))
this.messagesWaitingForProcessing++;
};
e.AfterMessageHandled += (thebus, headers, message, context, args) =>
{
this.messagesWaitingForProcessing--;
};
})
.Start();
}
public async Task WaitForMessagesProcessed()
{
this.DetermineMessagesWaitingForProcessing();
while (this.messagesWaitingForProcessing > 0)
{
this.bus.Advanced.Workers.SetNumberOfWorkers(2);
while (this.messagesWaitingForProcessing > 0)
{
await Task.Delay(100);
}
this.bus.Advanced.Workers.SetNumberOfWorkers(0);
this.DetermineMessagesWaitingForProcessing();
}
}
public void DetermineMessagesWaitingForProcessing() {
this.messagesWaitingForProcessing = Directory.GetFiles(GetDirectoryForQueueNamed(this.queueName), "*.rebusmessage.json").Count();
}
private static string GetDirectoryForQueueNamed(string queueName)
{
return Path.Combine(this.baseDiretory, queueName);
}
}
A test could be like
[TestMethod]
public void Test() {
var endpoint1 = LaunchExe("1");
var endpoint2 = LaunchExe("2");
endPoint1.DoSomeAction();
endPoint1.WaitForMessagesProcessed();
Assert.AreEqual("expectation", endPoint1.Query());
}
I have a requirement to start a process on the server that may run for several minutes, so I was thinking of exposing the following hub method:-
public async Task Start()
{
await Task.Run(() => _myService.Start());
}
There would also be a Stop() method that allows a client to stop the running process, probably via a cancellation token. I've also omitted code that prevents it from being started if already running, error handling, etc.
Additionally, the long-running process will be collecting data which it needs to periodically broadcast back to the client(s), so I was wondering about using an event - something like this:-
public async Task Start()
{
_myService.AfterDataCollected += AfterDataCollectedHandler;
await Task.Run(() => _myService.Start());
_myService.AfterDataCollected -= AfterDataCollectedHandler;
}
private void AfterDataCollectedHandler(object sender, MyDataEventArgs e)
{
Clients.All.SendData(e.Data);
}
Is this an acceptable solution or is there a "better" way?
You don't need to use SignalR to start the work, you can use the applications already existing framework / design / API for this and only use SignalR for the pub sub part.
I did this for my current customers project, a user starts a work and all tabs belonging to that user is updated using signalr, I used a out sun library called SignalR.EventAggregatorProxy to abstract the domain from SignalR. Disclaimer : I'm the author of said library
http://andersmalmgren.com/2014/05/27/client-server-event-aggregation-with-signalr/
edit: Using the .NET client your code would look something like this
public class MyViewModel : IHandle<WorkProgress>
{
public MyViewModel(IEventAggregator eventAggregator)
{
eventAggregator.Subscribe(this);
}
public void Handle(WorkProgress message)
{
//Act on work progress
}
}
if i receive a HttpServerRequest in a Handler, is it somehow possible to publish the request?
I want to implement a small demo website with an index.html and an unknown number of sub sites. At first there should be a main vert.x module, which starts the HttpServer. In this main module it should be possible to add other dependent modules. I will call them submodules now. I don't know how many submodules i will have later, but each submodule should contain the logic to handle the http response for a specific URL (the sub html files). I guess i have to do the same for the WebSocketHandler...
A small example of the code inside the start():
//My Main Module:
vertx.createHttpServer().requestHandler(new Handler<HttpServerRequest>() {
public void handle(HttpServerRequest req) {
vertx.eventBus().publish("HTTP_REQUEST_CONSTANT", req);
}
}).listen(8080);
// My submodule 1
vertx.eventBus().registerHandler("HTTP_REQUEST_CONSTANT", new Handler<HttpServerRequest>() {
#Override
public void handle(HttpServerRequest req) {
if (req.uri().equals("/")) {
req.response();
}
}
});
// Other submodules which handles other URLs
Or any other solutions? I just don't wanna have the logic for sub sites in the main module.
Edit: Or could i call the vertx.createHttpServer() method in each submodule?
I have a similar Vert.x based application and I ended up doing the following:
I have a HttpServerVerticle that is started from the MainVerticle. There I created an HttpServer with several matchers. Each matcher receives a request and forwards it to a dedicated verticle through theEventBus. Upon getting the response from a dedicated verticle it writes the answer to the response.
Here is a code snippet:
RouteMatcher restMatcher = new RouteMatcher();
EventBus eventBus = vertx.eventBus();
HttpServer httpServer = vertx.createHttpServer();
restMatcher.post("/your/url",
r -> {
r.bodyHandler(requestBody -> {
final int length = requestBody.length();
if(length == 0) {
//return bad request
r.response().setStatusCode(HttpResponseStatus.BAD_REQUEST.code());
r.response().end();
return;
}
eventBus.send("your.address.here",
requestBody.getString(0, length),
new Handler<Message<JsonObject>>(){
#Override
public void handle(Message<JsonObject> message) {
//return the response from the other verticle
r.response().setStatusCode(HttpResponseStatus.OK.code());
if (message.body() != null) {
r.response().end(message.body().toString());
}
else{
r.response().end();
}
}
});
});
});
httpServer.requestHandler(restMatcher);
httpServer.listen(yourPort,yourHost);
In the dedicated verticle you register a listener to the address:
vertx.eventBus().registerHandler("your.address.here", this::yourHandlerMethod);
The handler method would look something like the following:
protected void yourHandlerMethod(Message<String> message){
// do your magic, produce an answer
message.reply(answer);
}
This way you separate your logic from your HTTP mappings and can have different pieces of logic in separate verticles using multiple event bus addresses.
Hope this helps.
SignalR does not have the ability to have client methods which returns a value. So I am trying to create a helper class to make this possible.
So this is what I am trying to do:
Server side: Call client method and provide unique request id Client(clientId).GetValue(requestId)
Server side: Save requestId and wait for answer using ManualResetEvent
Client side: Inside void GetValue(Guid requestId) call server method hubProxy.Invoke("GetValueFinished", requestId, 10)
Server side: find waiting method by requestId => set return value => set signal
Server side: Method not longer waiting vor ManualResetEvent and returns retrieved value.
I am able to get it work unfortunately. Here is my code:
public static class MethodHandler
{
private static ConcurrentDictionary<Guid, ReturnWaiter> runningMethodWaiters = new ConcurrentDictionary<Guid,ReturnWaiter>();
public static TResult GetValue<TResult>(Action<Guid> requestValue)
{
Guid key = Guid.NewGuid();
ReturnWaiter returnWaiter = new ReturnWaiter(key);
runningMethodWaiters.TryAdd(key, returnWaiter);
requestValue.Invoke(key);
returnWaiter.Signal.WaitOne();
return (TResult)returnWaiter.Value;
}
public static void GetValueResult(Guid key, object value)
{
ReturnWaiter waiter;
if (runningMethodWaiters.TryRemove(key, out waiter))
{
waiter.Value = value;
}
}
}
internal class ReturnWaiter
{
private ManualResetEvent _signal = new ManualResetEvent(false);
public ManualResetEvent Signal { get { return _signal; } }
public Guid Key {get; private set;}
public ReturnWaiter(Guid key)
{
Key = key;
}
private object _value;
public object Value
{
get { return _value; }
set
{
_value = value;
Signal.Set();
}
}
}
Using this MethodHandler class I need to have two method server side:
public int GetValue(string clientId)
{
return MethodHandler.GetValue<int>(key => Clients(clientId).Client.GetValue(key));
}
public void GetValueResult(Guid key, object value)
{
MethodHandler.GetValueResult(key, value);
}
Client side implementation is like this:
// Method registration
_hubProxy.On("GetValue", new Action<Guid>(GetValue));
public void GetValue(Guid requestId)
{
int result = 10;
_hubConnection.Invoke("GetValueResult", requestId, result);
}
PROBLEM:
if I call server side GetValue("clientid"). The client method will not be invoked. If I comment out returnWaiter.Signal.WaitOne();, client side GetValue is called and server side GetValueResult is called. But of course this time the method has already returned.
I thought is has to do with the ManualResetEvent but even using while(!returnWaiter.HasValue) Thread.Sleep(100); will not fix this issue.
Any ideas how to fix this issue?
Thanks in advance!
First, I think that, rather than asking for help in how to make it synchronous, it would be best if you just told us what it is you're trying to do so we could suggest a proper approach to do it.
You don't show your MethodHandler::Retrieve method, but I can guess pretty much what it looks like and it's not even the real problem. I have to tell you in the nicest possible way that this is a really bad idea. It will simply never scale. This would only work with a single SignalR server instance because you're relying on machine specific resources (e.g. kernel objects behind the ManualResetEvent) to provide the blocking. Maybe you don't need to scale beyond one server to meet your requirements, but this still a terrible waste of resources even on a single server.
You're actually on the right track with the client calling back with the requestId as a correlating identifier. Why can't you use that correlation to resume logical execution of whatever process you are in the middle of on the server side? That way no resources are held around while waiting for the message to be delivered to the client, processed and then the follow up message, GetValueResult in your sample, to be sent back a the server instance.
Problem solved:
The problem only occured in Hub.OnConnected and Hub.OnDisconnected. I don't have an exact explanation why, but probably these methods must be able to finish before it will handle your method call to the client.
So I changed code:
public override Task OnConnected()
{
// NOT WORKING
Debug.Print(MethodHandler.GetValue<int>(key => Clients(Context.ConnectionId).Client.GetValue(key)));
// WORKING
new Thread(() => Debug.Print(MethodHandler.GetValue<int>(key => Clients(Context.ConnectionId).Client.GetValue(key)))).Start();
return base.OnConnected();
}
I've heard a LOT in the past about how programming with Threads and Tasks is very dangerous to the naive. Well, I'm naive, but I've got to learn sometime. I am making a program (really, it's a Generic Handler for ASP.Net) that needs to call to a 3rd party and wait for a response. While waiting, I'd like to have the handler continue doing some other things, so I am trying to figure out how to do the 3rd party web request asynchronously. Based on some answers to some other questions I've received, here is what I've come up with, but I want to make sure I won't get into big problems when my handler is called multiple time concurrently.
To test this I've built a console project.
class Program
{
static void Main(string[] args)
{
RunRequestAsynch test = new RunRequestAsynch();
test.TestingThreadSafety = Guid.NewGuid().ToString();
Console.WriteLine("Started:" + test.TestingThreadSafety);
Task tTest = new Task(test.RunWebRequest);
tTest.Start();
while (test.Done== false)
{
Console.WriteLine("Still waiting...");
Thread.Sleep(100);
}
Console.WriteLine("Done. " + test.sResponse);
Console.ReadKey();
}
}
I instantiate a separate object (RunRequestAsynch) set some values on it, and then start it. While that is processing I'm just outputting a string to the console window.
public class RunRequestAsynch
{
public bool Done = false;
public string sResponse = "";
public string sXMLToSend = "";
public string TestingThreadSafety = "";
public RunRequestAsynch() { }
public void RunWebRequest()
{
Thread.Sleep(500);
// HttpWebRequest stuff goes here
sResponse = TestingThreadSafety;
Done = true;
Thread.Sleep(500);
}
}
So...if I run 1000 of these simultaneously, I can count on the fact that each instance has its own memory and properties, right? And that the line "Done = true;" won't fire and then every one of the instances of the Generic Handler die, right?
I wrote a .bat file to run several instances, and the guid I set on each specific object seems to stay the same for each instance, which is what I want...but I want to make sure I'm not doing something really stupid that will bite me in the butt under full load.
I don't see any glaring problems, however you should consider using the Factory.StartNew instead of Start. Each task will only be executed once, so there isn't any problem with multiple tasks running simultaneously.
If you want to simplify your code a little and take advantage of the Factory.StartNew, in your handler you could do something like this (from what I remember of your last question):
Task<byte[]> task = Task.Factory.StartNew<byte[]>(() => // Begin task
{
//Replace with your web request, I guessed that it's downloading data
//change this to whatever makes sense
using (var wc = new System.Net.WebClient())
return wc.DownloadData("Some Address");
});
//call method to parse xml, will run in parallel
byte[] result = task.Result; // Wait for task to finish and fetch result.