How to convert this WebSocket pattern to a Task I can await/cancel/continuewith/ - websocket

I have 3rd party WebSocket that I need to consume where the request is sent in one method and the response is given in another. How can I convert this type of pattern to a more typical async/await TPL Task that will support cancellation (via token), continue with and all the other goodies.
This is what I came up with so far, although I'm not sure if it works. I can't test it until Monday.
So here are my questions:
Will this work?
I've been reading about TaskCompletionSource. Is there a better way to do any of this possibly with TaskCompletionSource?
I really don't like the lock because I know it has the potential to block for a long time but but I'm not sure how to do it any better because if I don't lock a second call to AsyncGetPositions could clear any positions already returned.
Even with the lock I know that if there is a timeout or cancellation that creates a problem so maybe I just remove the cancellation token. The only other thing I can think of would be to create multiple clients that are all authenticated and ready to process a request and then manage them like a thread pool for these types of request but I'm not going to be doing that anytime soon so other than that... idk.
private object GetPositionsLock = new object();
private IEnumerable<Position> Positions { get; } = new List<Position>();
private Task PositionsReturned { get; set; }
public async Task<List<Position>> AsyncGetPositions(CancellationToken token)
{
try
{
lock (GetPositionsLock)
{
Positions.Clear();
IbWebSocket.reqPositions();
PositionsReturned = new Task(null, token, TaskCreationOptions.None);
PositionsReturned.GetAwaiter().GetResult();
return token.IsCancellationRequested ? null : Positions.ToList().Where(x => x.Shares != 0).ToList();
}
}
catch (TimeoutException ex)
{
//LogTimeout
throw;
}
catch (Exception ex)
{
//LogError
throw;
}
}
/// <summary>
/// Provides a position to the reqPositions() method. When the last position has been received positionEnd() is called.
/// </summary>
/// <param name="contract"></param>
/// <param name="value"></param>
/// <param name="account"></param>
public void position(string account, Contract contract, double value)
{
try
{
Positions.Concat(new Position(account, contract, value));
}
catch (Exception ex)
{
//LogError
throw;
}
}
/// <summary>
/// Indicates all the positions have been transmitted.
/// </summary>
public void positionEnd()
{
PositionsReturned = Task.CompletedTask;
}

Will this work?
No. You shouldn't use the Task constructor, use lock with async code, or mix blocking with asynchronous code.
I've been reading about TaskCompletionSource. Is there a better way to do any of this possibly with TaskCompletionSource?
Yes, that's the type to use for this scenario.
I really don't like the lock because I know it has the potential to block for a long time but but I'm not sure how to do it any better because if I don't lock a second call to AsyncGetPositions could clear any positions already returned.
I recommend getting this working first, and then handling the additional requirement of reentrancy. Each of those are hard enough on their own.
What you want to do is have a TaskCompletionSource<T> and complete it when positionEnd is invoked. For simplicity, start without reentrancy concerns and without the CancellationToken. Once you fully understand TaskCompletionSource<T>, then you can add complexity:
private List<Position> Positions { get; } = new();
private TaskCompletionSource<List<Position>> PositionsReturned { get; set; }
public Task<List<Position>> AsyncGetPositions()
{
Positions.Clear();
PositionsReturned = new();
IbWebSocket.reqPositions();
return PositionsReturned.Task;
}
public void position(string account, Contract contract, double value)
{
Positions.Add(new Position(account, contract, value));
}
public void positionEnd()
{
PositionsReturned.TrySetResult(Positions);
}

Related

How to exit clean from WebAPI background service

The code below is a Web API that prints on behalf of a SPA. For brevity I've omitted using statements and the actual printing logic. That stuff all works fine. The point of interest is refactoring of the printing logic onto a background thread, with the web api method enqueuing a job. I did this because print jobs sent in quick succession were interfering with each other with only the last job printing.
It solves the problem of serialising print jobs but raises the question of how to detect shutdown and signal the loop to terminate.
namespace WebPrint.Controllers
{
public class LabelController : ApiController
{
static readonly ConcurrentQueue<PrintJob> queue = new ConcurrentQueue<PrintJob>();
static bool running = true;
static LabelController()
{
ThreadPool.QueueUserWorkItem((state) => {
while (running)
{
Thread.Sleep(30);
if (queue.TryDequeue(out PrintJob job))
{
this.Print(job);
}
}
});
}
public void Post([FromBody]PrintJob job)
{
queue.Enqueue(job);
}
}
public class PrintJob
{
public string url { get; set; }
public string html { get; set; }
public string printer { get; set; }
}
}
Given the way I acquire a thread to servicing the print queue, it is almost certainly marked as a background thread and should terminate when the app pool tries to exit, but I am not certain of this, and so I ask you, dear readers, for your collective notion of best practice in such a scenario.
Well, I did ask for best practice.
Nevertheless, I don't have long-running background tasks, I have short-running tasks. They arrive asynchronously on different threads, but must be executed serially and on a single thread because the WinForms printing methods are designed for STA threading.
Matt Lethargic's point about possible job loss is certainly a consideration, but for this case it doesn't matter. Jobs are never queued for more than a few seconds and loss would merely prompt operator retry.
For that matter, using a message queue doesn't solve the problem of "what if someone shuts it down while it's being used" it merely moves it to another piece of software. A lot of message queues aren't persistent, and you wouldn't believe the number of times I've seen someone use MSMQ to solve this problem and then fail to configure it for persistence.
This has been very interesting.
http://thecodelesscode.com/case/156
I would look at your architecture at a higher level, doing 'long running tasks' such as printing should probably live outside of you webapi process entirely.
If this we myself I would:
Create a windows service (or what have you) that has all the printing logic in it, the job of the controller is then to just talk to the service either by http or some kind of queue MSMQ, RabbitMQ, ServiceBus etc.
If via http then the service should internally queue up the print jobs and return 200/201 to the controller as soon as possible (before printing happens) so that the controller can return to the client efficiently and release it's resources.
If via a queuing technology then the controller should place a message on the queue and again return 200/201 as quick as possible, the service can then read the messages at it's own rate and print one at a time.
Doing it this way removes overhead from your api and also the possibility of losing print jobs in the case of a failure in the webapi (if the api crashes any background threads may/will be effected). Also what if you do a deployment at the point of someone printing, there's a high chance the print job will fail.
My 2 cents worth
I believe that the desired behavior is not something that should be done within a Controller.
public interface IPrintAgent {
void Enqueue(PrintJob job);
void Cancel();
}
The above abstraction can be implemented and injected into the controller using the frameworks IDependencyResolver
public class LabelController : ApiController {
private IPrintAgent agent;
public LabelController(IPrintAgent agent) {
this.agent = agent;
}
[HttpPost]
public IHttpActionResult Post([FromBody]PrintJob job) {
if (ModelState.IsValid) {
agent.Enqueue(job);
return Ok();
}
return BadRequest(ModelState);
}
}
The sole job of the controller in the above scenario is to queue the job.
Now with that aspect out of the way I will focus on the main part of the question.
As already mentioned by others, there are many ways to achieve the desired behavior
A simple in memory implementation can look like
public class DefaultPrintAgent : IPrintAgent {
static readonly ConcurrentQueue<PrintJob> queue = new ConcurrentQueue<PrintJob>();
static object syncLock = new Object();
static bool idle = true;
static CancellationTokenSource cts = new CancellationTokenSource();
static DefaultPrintAgent() {
checkQueue += OnCheckQueue;
}
private static event EventHandler checkQueue = delegate { };
private static async void OnCheckQueue(object sender, EventArgs args) {
cts = new CancellationTokenSource();
PrintJob job = null;
while (!queue.IsEmpty && queue.TryDequeue(out job)) {
await Print(job);
if (cts.IsCancellationRequested) {
break;
}
}
idle = true;
}
public void Enqueue(PrintJob job) {
queue.Enqueue(job);
if (idle) {
lock (syncLock) {
if (idle) {
idle = false;
checkQueue(this, EventArgs.Empty);
}
}
}
}
public void Cancel() {
if (!cts.IsCancellationRequested)
cts.Cancel();
}
static Task Print(PrintJob job) {
//...print job
}
}
which takes advantage of async event handlers to process the queue in sequence as jobs are added.
The Cancel is provided so that the process can be short circuited as needed.
Like in Application_End event as suggested by another user
var agent = new DefaultPrintAgent();
agent.Cancel();
or manually by exposing an endpoint if so desired.

Handle Hibernate optimistic locking with Spring

I am using Hibernate and Spring Data, it will perform optimistic locking when insert or update an entity, and if the version in database doesn't match with the one to persist, it will throw exception StaleObjectStateException, in Spring, you need to catch it with ObjectOptimisticLockingFailureException.
What I want to do is catch the exception and ask the user to refresh the page in order to get the latest data from database like below:
public void cancelRequest()
{
try
{
request.setStatus(StatusEnum.CANCELLED);
this.request = topUpRequestService.insertOrUpdate(request);
loadRequests();
//perform other tasks...
} catch (ObjectOptimisticLockingFailureException ex)
{
FacesUtils.showErrorMessage(null, "Action Failed.", FacesUtils.getMessage("message.pleaseReload"));
}
}
I assume it will also work with the code below but I have not tested it yet.
public void cancelRequest()
{
RequestModel latestModel = requestService.findOne(request.getId());
if(latestModel.getVersion() != request.getVersion())
{
FacesUtils.showErrorMessage(null, "Action Failed.", FacesUtils.getMessage("message.pleaseReload"));
}
else
{
request.setStatus(StatusEnum.CANCELLED);
this.request = requestService.insertOrUpdate(request);
loadRequests();
//perform other tasks...
}
}
I need to apply this checking on everywhere I call requestService.insertOrUpdate(request); and I don't want to apply them one by one. Therefore, I decide to place the checking code inside the function insertOrUpdate(entity) itself.
#Transactional
public abstract class BaseServiceImpl<M extends Serializable, ID extends Serializable, R extends JpaRepository<M, ID>>
implements BaseService<M, ID, R>
{
protected R repository;
protected ID id;
#Override
public synchronized M insertOrUpdate(M entity)
{
try
{
return repository.save(entity);
} catch (ObjectOptimisticLockingFailureException ex)
{
FacesUtils.showErrorMessage(null, FacesUtils.getMessage("message.actionFailed"),
FacesUtils.getMessage("message.pleaseReload"));
return entity;
}
}
}
My main question is, there will be one problem with this approach. The caller side will not know whether the entity persisted successfully or not since the exception will be caught and handled inside the function, so the caller side will always assume the persist was success, and continue do the other tasks, which is I don't want. I want it to stop performing tasks if fail to persist:
public void cancelRequest()
{
try
{
request.setStatus(StatusEnum.CANCELLED);
this.request = topUpRequestService.insertOrUpdate(request);
//I want it to stop here if fail to persist, don't load the requests and perform other tasks.
loadRequests();
//perform other tasks...
} catch (ObjectOptimisticLockingFailureException ex)
{
FacesUtils.showErrorMessage(null, "Action Failed.", FacesUtils.getMessage("message.pleaseReload"));
}
}
I know when calling the insertOrUpdate , I can catch the returned entiry by declaring new model variable, and compare it's version to the original one, if version is same, means the persistance was failed. But if I doing it this way, I have to write the version checking code on everywhere I call insertOrUpdate. Any better approach then this?
The closest way to being able to do this and not having to necessarily make significant code changes at all the invocation points would be to look into some type of Spring AOP advice that works similar to Spring's #Transactional annotation.
#FacesReloadOnException( ObjectOptimisticLockingFailureException.class )
public void theRequestHandlerMethod() {
// call your service here
}
The idea is that the #FacesReloadOnException annotation triggers an around advice that catches any exception provided in the annotation value and does basically handles the call the FacesUtils should any of those exception classes be thrown.
The other options you have available aren't going to be nearly as straight forward and will require that you touch all your usage points in some fashion, its just inevitable.
But I certainly would not consider putting the try/catch block in the service tier if you don't want to alter your service tier's method return types because the controllers are going to need more context as you've pointed out. The only way to push that try/catch block downstream would be if you returned some type of Result object that your controller could then inspect like
public void someControllerRequestMethod() {
InsertOrUpdateResult result = yourService.insertOrUpdate( theObject );
if ( result.isSuccess() ) {
loadRequests();
}
else {
FacesUtils.showErrorMessage( ... );
}
}
Otherwise you'd need to get creative if you want to somehow centralize this in your web tier. Perhaps a web tier utility class that mimics your BaseService interface like the following:
public <T extends BaseService, U> U insertOrUpdate(T service, U object, Consumer<U> f) {
try {
U result = service.insertOrUpdate( object );
f.accept( result );
return result;
}
catch ( ObjectOptimisticLockingFailureException e ) {
FacesUtils.showErrorMessage( ... );
}
}
But being frank, unless you have a lot of call sites that are similar enough to where such a generalization with a consumer like this makes sense, you may find its more effort and work to generalize it than it would to just place the try/catch block in the controller itself.

Ninject InRequestScope sometimes seems to return a wrong instance

I am developing an MVC 5 application that uses Ninject to handle dependency injection. The application defines a SecurityService that provided various information about current logged user. I am using Windows Authentication.
Ok, let's dive into the code.
NinjectWebCommon.cs
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
private static KernelBase kernel;
/// <summary>
/// Starts the application
/// </summary>
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
bootstrapper.Initialize(CreateKernel);
}
/// <summary>
/// Stops the application.
/// </summary>
public static void Stop()
{
bootstrapper.ShutDown();
}
/// <summary>
/// Creates the kernel that will manage your application.
/// </summary>
/// <returns>The created kernel.</returns>
private static IKernel CreateKernel()
{
kernel = new StandardKernel();
try
{
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
return kernel;
}
catch
{
kernel.Dispose();
throw;
}
}
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<ISecurityService>().To<SecurityService>().InRequestScope();
// custom bindings are defined here
}
public static void PerformInjectionOn(object instance)
{
kernel.Inject(instance);
}
Please, notice kernel.Bind<ISecurityService>().To<SecurityService>().InRequestScope(); for security binding definition.
SecurityService.cs
private AppUser _CurrentUser = null;
/// <summary>
/// gets logged user data, based on current identity username (Sam account name)
/// </summary>
/// <returns>AppUser object if windows identity maps to an existing active user. Otherwise null</returns>
public AppUser GetLoggedUserData()
{
lock(lockObj)
{
String currUsername = WindowsIdentity.GetCurrent().Name;
// comparison between current user name and actually authenticated user is needed since some requests end with different values!
if (_CurrentUser == null || !_CurrentUser.Username.Equals(currUsername))
{
_CurrentUser = _ScopedDataAccess.AppUserRepository.AllNoTracking
// some includes
.SingleOrDefault(u => u.IsEnabled && u.Username.Equals(currUsername));
if (_CurrentUser == null)
{
logger.LogEx(LogLevel.Info, "GetLoggedUserData - user {0} authentication failed", currUsername);
return null;
}
}
return _CurrentUser;
}
}
My problem is that, even if SecurityService is instantiated per request, sometimes I receive an instance where _CurrentUser.Username is different from currUsername (i.e. both are valid A/D users with which I perform the test).
Current workaround is to have !_CurrentUser.Username.Equals(currUsername) to invalidate cached user instance, if request authenticated user is different from cached one, but I would like to know what is happening.
Just out of curiosity, I have checked InThreadScope and had the same problem, but I think this can be explained by the fact that the thread pool used by IIS may provide the same thread for another request.
Does anyone know why InRequestScope behaves like this?
Thanks.
[edit]
Call stack when current user is different from cached one:
ProjectName.Models.dll!ProjectName.Models.SecurityService.GetLoggedUserData() Line 54 C#
ProjectName.Models.dll!ProjectName.Models.SecurityService.GetAndCheckUserData() Line 76 C#
ProjectName.Models.dll!ProjectName.Models.SecurityService.IsAdmin.get() Line 98 C#
ProjectName.Models.dll!ProjectName.Models.EntitiesCache.ProjectStatuses.get() Line 51 C#
ProjectName.Services.dll!ProjectName.Services.ProjectService.CreateSelectorsDomain() Line 253 C#
ProjectName.Services.dll!ProjectName.Services.ProjectService.ProjectService(ProjectName.Models.ISecurityService securityService, ProjectName.Models.IEntitiesCache entitiesCache, ProjectName.Models.IScopedDataAccess dataAccess, ProjectName.Services.IProjectTemplateService projectTemplateService) Line 33 C#
[External Code]
ProjectName.Web.dll!ProjectName.Web.NinjectWebCommon.PerformInjectionOn(object instance) Line 93 C#
ProjectName.Web.dll!ProjectName.Web.BaseController.BaseController() Line 21 C#
[External Code]
The logic in all steps in synchronous (no async, await, no Tasks)

MassTransit and event versus command publishing

I'm new to MassTransit, and I miss something in my understanding.
Let's say I have a server farm were all nodes can do the same job. The application framework is CQRS's styled. That means I have two base kind of message to publish :
Commands : must be handled by exactly one of the server, any of them (the first with job slot free)
Events : must be handled by all servers
I've have build an extremely simple MassTransit prototype (a console application that is sending hello every X seconds).
In the API, I can see there is a "publish" method. How can I specify what kind of message it is (one versus all server)?
If I look a the "handler" configuration, I can specify the queue uri. If I specify the same queue for all hosts, all hosts will get the message, but I cannot limit the execution to only one server.
If I listen from a host dedicated queue, only one server will handle the messages, but I don't know how to broadcast the other kind of message.
Please help me to understand what I'm missing.
PS: if it cares, my messaging system is rabbitmq.
In order to test, I have create a common class library with this classes :
public static class ActualProgram
{
private static readonly CancellationTokenSource g_Shutdown = new CancellationTokenSource();
private static readonly Random g_Random = new Random();
public static void ActualMain(int delay, int instanceName)
{
Thread.Sleep(delay);
SetupBus(instanceName);
Task.Factory.StartNew(PublishRandomMessage, g_Shutdown.Token);
Console.WriteLine("Press enter at any time to exit");
Console.ReadLine();
g_Shutdown.Cancel();
Bus.Shutdown();
}
private static void PublishRandomMessage()
{
Bus.Instance.Publish(new Message
{
Id = g_Random.Next(),
Body = "Some message",
Sender = Assembly.GetEntryAssembly().GetName().Name
});
if (!g_Shutdown.IsCancellationRequested)
{
Thread.Sleep(g_Random.Next(500, 10000));
Task.Factory.StartNew(PublishRandomMessage, g_Shutdown.Token);
}
}
private static void SetupBus(int instanceName)
{
Bus.Initialize(sbc =>
{
sbc.UseRabbitMqRouting();
sbc.ReceiveFrom("rabbitmq://localhost/simple" + instanceName);
sbc.Subscribe(subs =>
{
subs.Handler<Message>(MessageHandled);
});
});
}
private static void MessageHandled(Message msg)
{
ConsoleColor color = ConsoleColor.Red;
switch (msg.Sender)
{
case "test_app1":
color = ConsoleColor.Green;
break;
case "test_app2":
color = ConsoleColor.Blue;
break;
case "test_app3":
color = ConsoleColor.Yellow;
break;
}
Console.ForegroundColor = color;
Console.WriteLine(msg.ToString());
Console.ResetColor();
}
private static void MessageConsumed(Message msg)
{
Console.WriteLine(msg.ToString());
}
}
public class Message
{
public long Id { get; set; }
public string Sender { get; set; }
public string Body { get; set; }
public override string ToString()
{
return string.Format("[{0}] {1} : {2}" + Environment.NewLine, Id, Sender, Body);
}
}
I have also 3 console applications that just run the ActualMain method :
internal class Program
{
private static void Main(string[] args)
{
ActualProgram.ActualMain(0, 1);
}
}
What you want is known as Competing Consumers (search SO for that you'll find more info)
Using RabbitMQ makes life easy, all you need to do is specify the same queue name for each consumer you start, the message will be processed by only one of them.
Instead of generating a unique queue each time as you are doing.
private static void SetupBus(int instanceName)
{
Bus.Initialize(sbc =>
{
sbc.UseRabbitMqRouting();
sbc.ReceiveFrom("rabbitmq://localhost/Commands);
sbc.Subscribe(subs =>
{
subs.Handler<Message>(MessageHandled);
});
});
}
AFAIK, you'll need to have a separate process for command handlers as opposed to event handlers. All the command handlers will ReceiveFrom the same queue, all event handlers will ReceiveFrom their own unique queue.
The other piece of the puzzle is how you get messages into the bus. You can still use publish for commands, but if you have configured consumers incorrectly you could get multiple executions as the message will go to all consumers, if you want to guarantee the message ends up on a single queue you can use Send rather than Publish.
Bus.Instance
.GetEndpoint(new Uri("rabbitmq://localhost/Commands"))
.Send(new Message
{
Id = g_Random.Next(),
Body = "Some message",
Sender = Assembly.GetEntryAssembly().GetName().Name
});

Sterling serialization problem on Windows Phone 7

I have a problem with Sterling Database for Windows Phone. I implemented the database step by step in my wp7app, but it doesn't serialize my data when new entities are saved. For example: I serialize credentials using sterling database:
var userCredentials = new UserCredentials(userName, password);
App.Database.Save(userCredentials);
App.Database.Flush();
But when the application is reactivated (or re-launched) Sterling doesn't return any values from isolated storage:
var firstOrDefault = App.Database.Query<UserCredentials, string>()
.ToList()
.FirstOrDefault();
My ActivateEngine method looks are standard and TableDefinition is:
CreateTableDefinition< UserCredentials, string >(t => t.UserName),
Why is sterling database doesn't serialize my data? Everything seems to be implemented fine. Please help.
Are you activating and registering the database on startup and diposing on completion as described in the Quickstart?
My personal preference is to use an application service similar to the following:
namespace MyApp.Data
{
using System.Windows;
using Wintellect.Sterling;
using Wintellect.Sterling.IsolatedStorage;
///
/// Defines a an application service that supports the Sterling database.
///
public class SterlingDatabaseService : IApplicationService, IApplicationLifetimeAware
{
public static SterlingDatabaseService Current { get; private set; }
public ISterlingDatabaseInstance Database { get; private set; }
private SterlingEngine _engine;
///
/// Called by an application in order to initialize the application extension service.
///
/// Provides information about the application state.
public void StartService(ApplicationServiceContext context)
{
Current = this;
_engine = new SterlingEngine();
}
///
/// Called by an application in order to stop the application extension service.
///
public void StopService()
{
_engine = null;
}
///
/// Called by an application immediately before the event occurs.
///
public void Starting()
{
_engine.Activate();
Database = _engine
.SterlingDatabase
.RegisterDatabase(new IsolatedStorageDriver());
}
///
/// Called by an application immediately after the event occurs.
///
public void Started()
{
return;
}
///
/// Called by an application immediately before the event occurs.
///
public void Exiting()
{
_engine.Dispose();
}
///
/// Called by an application immediately after the event occurs.
///
public void Exited()
{
return;
}
}
}
If you use this approach, don't forget to add an instance in App.xaml:
<Application.ApplicationLifetimeObjects>
<!-- Required object that handles lifetime events for the application. -->
<shell:PhoneApplicationService Activated="Application_Activated"
Closing="Application_Closing"
Deactivated="Application_Deactivated"
Launching="Application_Launching" />
<data:SterlingDatabaseService />
</Application.ApplicationLifetimeObjects>

Resources