Detecting MSMQ errors - c#

I have this following code (verbatim) that I expect to generate a error:
using System.Messaging;
namespace MsmqTest
{
class Program
{
static void Main()
{
string invalidQueue = #"FormatName:DIRECT=OS:sometrahsname\private$\anothertrahsname";
Enqueue("test",invalidQueue);
}
private static void Enqueue(object o, string queueName)
{
using (MessageQueue msmq = new MessageQueue(queueName))
using (MessageQueueTransaction transaction = new MessageQueueTransaction())
{
msmq.DefaultPropertiesToSend.Recoverable = true;
transaction.Begin();
msmq.Send(new Message(o), transaction);
transaction.Commit();
}
}
}
}
Here we are sending a message to a queue on a server that does not exist. I expect to receive an indication that something went wrong. I do not get any. How do I check for error in this scenario?
Note: in order to run the code above you need to have MSMQ installed on your machine.

I stumbled about this problem before in one of my applications. MSDN documented that in MessageQueue.Send, the message might be sent to the dead-letter queue without throwing an exception. And that is what you are experiencing right now. What I did is to check if the queue exists.
using System;
using System.Messaging;
namespace MsmqTest
{
class Program
{
static void Main(string[] args)
{
string invalidQueue = #"FormatName:DIRECT=OS:sometrahsname\private$\anothertrahsname";
Enqueue("test", invalidQueue);
}
private static void Enqueue(object o, string queueName)
{
try
{
MessageQueue msmq = null;
//check if queueName exists
//it also validates if you have access to MSMQ server
if (!MessageQueue.Exists(queueName))
{
msmq = MessageQueue.Create(queueName);
//you can also set the permission here
//because the other application that may be reading
//has different account with the application that created the queue
//set to Everyone for demonstration purposes
msmq.SetPermissions("Everyone", MessageQueueAccessRights.FullControl);
}
else
{
msmq = new MessageQueue(queueName);
}
using (msmq)
{
using (MessageQueueTransaction transaction = new MessageQueueTransaction())
{
msmq.DefaultPropertiesToSend.Recoverable = true;
transaction.Begin();
msmq.Send(new Message(o), transaction);
transaction.Commit();
}
}
}catch(Exception)
{
//handle error here
}
}
}
}

Related

Only one usage of each socket address (protocol/network address/port) is normally permitted when AppPool is recycled

I have a .net Core application hosted on IIS.
The application initializes WebSocketServer, by adding a wrapper class as a HostedService.
The hosted service execute the Start() method seen below on its StartAsync() and the Destroy() method on its StopAsync() method.
The problem that whenever the related application pool is recycled - the error in the title appears ("Only one usage of each socket address (protocol/network address/port) is normally permitted"). It happens because there is a new working process that starts-up and trying to use the ports of the socket before there is a shutdown of the current Working process which still use the socket with the same ports.
I'm trying to find a way of avoiding that situation, programmatically or by configuration.
Here is my code of the HostedService:
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using System;
using System.Diagnostics;
using System.Linq;
using System.Net.WebSockets;
using WebSocketSharp.Server;
namespace XXXX
{
public class WebsocketServerWrapper
{
// Thats an websocket server , he will host our service as web socket service.
private static WebSocketServer wss;
private static readonly object LockObject = new object();
public static IConfiguration Config { get; set; }
public static bool IsCreated()
{
return wss != null;
}
public static bool HasChannels()
{
if(IsCreated())
{
return wss.WebSocketServices.Paths.Any();
}
return false;
}
public static bool IsListening()
{
if (wss != null)
{
return wss.IsListening;
}
return false;
}
public static void AddChannel(string channel)
{
if (wss.WebSocketServices.Paths.Any((path) => path == channel) == false)
{
wss.AddWebSocketService(channel,() => new <class that treats the socket behaviour itself>(Config));
}
}
public static bool Start()
{
wss.Start();
if (IsListening())
{
return true;
}
else
{
return false;
}
}
public static bool Destroy()
{
var isDestroyed = false;
if(IsCreated())
{
removeWebSocketServices();
wss.Stop();
wss = null;
isDestroyed = true;
}
return isDestroyed;
}
internal static void removeWebSocketServices()
{
var channels = wss?.WebSocketServices?.Paths?.ToList() ?? null;
if (channels != null)
{
channels.ForEach(channel => { wss.RemoveWebSocketService(channel); channel = null; });
}
}
public static bool CreateWSSServer()
{
bool isCreationSucceeded = false;
if(!IsCreated())
{
lock(LockObject)
{
try
{
var wssUrl = Config.GetValue<string>(<WebsocketServerUrl adress>);
wss = new WebSocketServer($"ws://{wssUrl}");
isCreationSucceeded = true;
}
catch (WebSocketException wse)
{
Debug.WriteLine(wse);
return isCreationSucceeded;
}
catch (Exception e)
{
Debug.WriteLine(e);
return isCreationSucceeded;
}
}
}
isCreationSucceeded = true;
return isCreationSucceeded;
}
}
}
I found a solution to that scenario (edited it in the question) - it turns out that the scenario of the server starts-up with new worker process before the "old" worker process shutdown is not rare - there is a parameter in the application pool under Recycling => Disable Overlapped Recycle - if it set to true (it is false by default), then the startup with new Working process will occur only after the current worker process will shut-down

Azure Service Bus Topics and Subscriptions with Worker Role

So I've recently gotten the need to use Service Bus Topic and Subscriptions and I've followed many articles and tutorials. I've been able to successfully implement Microsoft's Get started with Service Bus topics and also successfully used Visual Studio 2017's Worker Role template to access a database.
However, I'm confused as to how to properly "combine" the two. While the Get started with Service Bus topics article shows how to create 2 apps, one to send and one to receive and then quits, the Worker Role template seems to loops endlessly with await Task.Delay(10000);.
I'm not sure how to "mesh" the two properly. Essentially, I want my Worker Role to stay alive and listen for entries into it's subscription forever (or until it quits obviously).
Any guidance would be great!
P.S.: I've asked a related question concerning proper technology I should use for my case scenario at StackExchange - Software Engineering if you are interested.
Update #1 (2018/08/09)
Based on Arunprabhu's answer, here is some code of how I'm sending a Message based on articles I've read and receiving using Visual Studio 2017's Worker Role with Service Bus Queue template.
Sending (based on Get started with Service Bus topics)
using System;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Azure.ServiceBus;
namespace TopicsSender {
internal static class Program {
private const string ServiceBusConnectionString = "<your_connection_string>";
private const string TopicName = "test-topic";
private static ITopicClient _topicClient;
private static void Main(string[] args) {
MainAsync().GetAwaiter().GetResult();
}
private static async Task MainAsync() {
const int numberOfMessages = 10;
_topicClient = new TopicClient(ServiceBusConnectionString, TopicName);
Console.WriteLine("======================================================");
Console.WriteLine("Press ENTER key to exit after sending all the messages.");
Console.WriteLine("======================================================");
// Send messages.
await SendMessagesAsync(numberOfMessages);
Console.ReadKey();
await _topicClient.CloseAsync();
}
private static async Task SendMessagesAsync(int numberOfMessagesToSend) {
try {
for (var i = 0; i < numberOfMessagesToSend; i++) {
// Create a new message to send to the topic
var messageBody = $"Message {i}";
var message = new Message(Encoding.UTF8.GetBytes(messageBody));
// Write the body of the message to the console
Console.WriteLine($"Sending message: {messageBody}");
// Send the message to the topic
await _topicClient.SendAsync(message);
}
} catch (Exception exception) {
Console.WriteLine($"{DateTime.Now} :: Exception: {exception.Message}");
}
}
}
}
Receiving (based on Worker Role with Service Bus Queue template)
using System;
using System.Diagnostics;
using System.Net;
using System.Threading;
using Microsoft.ServiceBus.Messaging;
using Microsoft.WindowsAzure.ServiceRuntime;
namespace WorkerRoleWithSBQueue1 {
public class WorkerRole : RoleEntryPoint {
// The name of your queue
private const string ServiceBusConnectionString = "<your_connection_string>";
private const string TopicName = "test-topic";
private const string SubscriptionName = "test-sub1";
// QueueClient is thread-safe. Recommended that you cache
// rather than recreating it on every request
private SubscriptionClient _client;
private readonly ManualResetEvent _completedEvent = new ManualResetEvent(false);
public override void Run() {
Trace.WriteLine("Starting processing of messages");
// Initiates the message pump and callback is invoked for each message that is received, calling close on the client will stop the pump.
_client.OnMessage((receivedMessage) => {
try {
// Process the message
Trace.WriteLine("Processing Service Bus message: " + receivedMessage.SequenceNumber.ToString());
var message = receivedMessage.GetBody<byte[]>();
Trace.WriteLine($"Received message: SequenceNumber:{receivedMessage.SequenceNumber} Body:{message.ToString()}");
} catch (Exception e) {
// Handle any message processing specific exceptions here
Trace.Write(e.ToString());
}
});
_completedEvent.WaitOne();
}
public override bool OnStart() {
// Set the maximum number of concurrent connections
ServicePointManager.DefaultConnectionLimit = 12;
// Initialize the connection to Service Bus Queue
_client = SubscriptionClient.CreateFromConnectionString(ServiceBusConnectionString, TopicName, SubscriptionName);
return base.OnStart();
}
public override void OnStop() {
// Close the connection to Service Bus Queue
_client.Close();
_completedEvent.Set();
base.OnStop();
}
}
}
Update #2 (2018/08/10)
After a few suggestions from Arunprabhu and knowing I was using different libraries, below is my current solution with pieces taken from several sources. Is there anything I'm overlooking, adding that shouldering be there, etc? Currently getting an error that may be for another question or already answered so don't want to post it yet before further research.
using System;
using System.Diagnostics;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Azure.ServiceBus;
using Microsoft.WindowsAzure.ServiceRuntime;
namespace WorkerRoleWithSBQueue1 {
public class WorkerRole : RoleEntryPoint {
private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
private readonly ManualResetEvent _runCompleteEvent = new ManualResetEvent(false);
// The name of your queue
private const string ServiceBusConnectionString = "<your_connection_string>";
private const string TopicName = "test-topic";
private const string SubscriptionName = "test-sub1";
// _client is thread-safe. Recommended that you cache
// rather than recreating it on every request
private SubscriptionClient _client;
public override void Run() {
Trace.WriteLine("Starting processing of messages");
try {
this.RunAsync(this._cancellationTokenSource.Token).Wait();
} catch (Exception e) {
Trace.WriteLine("Exception");
Trace.WriteLine(e.ToString());
} finally {
Trace.WriteLine("Finally...");
this._runCompleteEvent.Set();
}
}
public override bool OnStart() {
// Set the maximum number of concurrent connections
ServicePointManager.DefaultConnectionLimit = 12;
var result = base.OnStart();
Trace.WriteLine("WorkerRole has been started");
return result;
}
public override void OnStop() {
// Close the connection to Service Bus Queue
this._cancellationTokenSource.Cancel();
this._runCompleteEvent.WaitOne();
base.OnStop();
}
private async Task RunAsync(CancellationToken cancellationToken) {
// Configure the client
RegisterOnMessageHandlerAndReceiveMessages(ServiceBusConnectionString, TopicName, SubscriptionName);
_runCompleteEvent.WaitOne();
Trace.WriteLine("Closing");
await _client.CloseAsync();
}
private void RegisterOnMessageHandlerAndReceiveMessages(string connectionString, string topicName, string subscriptionName) {
_client = new SubscriptionClient(connectionString, topicName, subscriptionName);
var messageHandlerOptions = new MessageHandlerOptions(ExceptionReceivedHandler) {
// Maximum number of concurrent calls to the callback ProcessMessagesAsync(), set to 1 for simplicity.
// Set it according to how many messages the application wants to process in parallel.
MaxConcurrentCalls = 1,
// Indicates whether MessagePump should automatically complete the messages after returning from User Callback.
// False below indicates the Complete will be handled by the User Callback as in `ProcessMessagesAsync` below.
AutoComplete = false,
};
_client.RegisterMessageHandler(ProcessMessageAsync, messageHandlerOptions);
}
private async Task ProcessMessageAsync(Message message, CancellationToken token) {
try {
// Process the message
Trace.WriteLine($"Received message: SequenceNumber:{message.SystemProperties.SequenceNumber} Body:{Encoding.UTF8.GetString(message.Body)}");
await _client.CompleteAsync(message.SystemProperties.LockToken);
} catch (Exception e) {
// Handle any message processing specific exceptions here
Trace.Write(e.ToString());
await _client.AbandonAsync(message.SystemProperties.LockToken);
}
}
private static Task ExceptionReceivedHandler(ExceptionReceivedEventArgs exceptionReceivedEventArgs) {
Console.WriteLine($"Message handler encountered an exception {exceptionReceivedEventArgs.Exception}.");
var context = exceptionReceivedEventArgs.ExceptionReceivedContext;
Console.WriteLine("Exception context for troubleshooting:");
Console.WriteLine($"- Endpoint: {context.Endpoint}");
Console.WriteLine($"- Entity Path: {context.EntityPath}");
Console.WriteLine($"- Executing Action: {context.Action}");
return Task.CompletedTask;
}
}
}
Considering the complexity of the updated question Update #1 (2018/08/09), I am providing a separate answer.
The sender and receiver are using different libraries.
Sender - Microsoft.Azure.ServiceBus
Receiver - WindowsAzure.ServiceBus
Microsoft.Azure.ServiceBus has the message object as Message, where WindowsAzure.ServiceBus has BrokeredMessage.
There is a method RegisterMessageHandler available in Microsoft.Azure.ServiceBus, this is the alternative for client.OnMessage() in WindowsAzure.ServiceBus. By using this, the listener receives the message as Message object. This library supports asynchronous programming as you expect.
Refer here for samples from both the libraries.
If you are using Visual Studio, there is a default template available for creating Azure Cloud Service and Worker Role with Service Bus Queue. There you need to change the QueueClient with SubscriptionClient in WorkerRole.cs.
Then, the worker role will stay active, listening for the messages from Topic Subscription.
You can find the samples here. You should create Worker role with Service Bus Queue inside the Cloud Service

PushSharp Separation of Concerns

I'm currently working on a C# web application and I'm trying to get push notifications to work using the PushSharp package. I have all of my code for pushing notifications in the Global.asax file in my project, but I keep getting the error:
The collection has been marked as complete with regards to additions.
Here is my Global.asax file:
using BYC.Models;
using BYC.Models.Enums;
using Newtonsoft.Json.Linq;
using PushSharp.Apple;
using PushSharp.Google;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
namespace BYC
{
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
protected void Application_End()
{
PushBrokerSingleton pbs = new PushBrokerSingleton();
pbs.SendQueuedNotifications();
}
}
public sealed class PushBrokerSingleton
{
private static ApnsServiceBroker Apns { get; set; }
private static GcmServiceBroker Gcm { get; set; }
private static bool ApnsStarted = false;
private static bool GcmStarted = false;
private static object AppleSyncVar = new object();
private static object GcmSyncVar = new object();
private static readonly log4net.ILog log = log4net.LogManager.GetLogger
(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
public PushBrokerSingleton()
{
if (Apns == null)
{
string thumbprint = (AppSettings.Instance["APNS:Thumbprint"]);
X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
ApnsConfiguration.ApnsServerEnvironment production = Convert.ToBoolean(AppSettings.Instance["APNS:Production"]) ?
ApnsConfiguration.ApnsServerEnvironment.Production : ApnsConfiguration.ApnsServerEnvironment.Sandbox;
X509Certificate2 appleCert = store.Certificates
.Cast<X509Certificate2>()
.SingleOrDefault(c => string.Equals(c.Thumbprint, thumbprint, StringComparison.OrdinalIgnoreCase));
ApnsConfiguration apnsConfig = new ApnsConfiguration(production, appleCert);
Apns = new ApnsServiceBroker(apnsConfig);
Apns.OnNotificationFailed += (notification, aggregateEx) => {
aggregateEx.Handle(ex => {
// See what kind of exception it was to further diagnose
if (ex is ApnsNotificationException)
{
var notificationException = ex as ApnsNotificationException;
// Deal with the failed notification
var apnsNotification = notificationException.Notification;
var statusCode = notificationException.ErrorStatusCode;
log.Error($"Notification Failed: ID={apnsNotification.Identifier}, Code={statusCode}");
}
else {
// Inner exception might hold more useful information like an ApnsConnectionException
log.Error($"Notification Failed for some (Unknown Reason) : {ex.InnerException}");
}
// Mark it as handled
return true;
});
};
Apns.OnNotificationSucceeded += (notification) => {
log.Info("Notification Successfully Sent to: " + notification.DeviceToken);
};
}
if(Gcm == null)
{
GcmConfiguration gcmConfig = new GcmConfiguration(AppSettings.Instance["GCM:Token"]);
Gcm = new GcmServiceBroker(gcmConfig);
}
}
public bool QueueNotification(Notification notification, Device device)
{
if (!ApnsStarted)
{
ApnsStarted = true;
lock (AppleSyncVar)
{
Apns.Start();
}
}
if(!GcmStarted)
{
GcmStarted = true;
lock (GcmSyncVar)
{
Gcm.Start();
}
}
switch (device.PlatformType)
{
case PlatformType.iOS:
return QueueApplePushNotification(notification, device.PushRegistrationToken);
case PlatformType.Android:
return QueueAndroidPushNotification(notification, device.PushRegistrationToken);
default: return false;
}
}
private bool QueueApplePushNotification(Notification notification, string pushNotificationToken)
{
string appleJsonFormat = "{\"aps\": {\"alert\":" + '"' + notification.Subject + '"' + ",\"sound\": \"default\", \"badge\": " + notification.BadgeNumber + "}}";
lock (AppleSyncVar)
{
Apns.QueueNotification(new ApnsNotification()
{
DeviceToken = pushNotificationToken,
Payload = JObject.Parse(appleJsonFormat)
});
}
return true;
}
private bool QueueAndroidPushNotification(Notification notification, string pushNotificationToken)
{
string message = "{\"alert\":\"" + notification.Subject + "\",\"badge\":" + notification.BadgeNumber + "\"}";
lock (GcmSyncVar)
{
Gcm.QueueNotification(new GcmNotification()
{
RegistrationIds = new List<string>
{
pushNotificationToken
},
Data = JObject.Parse(message),
Notification = JObject.Parse(message)
});
}
return true;
}
public void SendQueuedNotifications()
{
if(Apns != null)
{
if (ApnsStarted)
{
lock(AppleSyncVar){
Apns.Stop();
log.Info("Sent Apns Notifications");
ApnsStarted = false;
}
}
}
if(Gcm != null)
{
if (GcmStarted)
{
lock (GcmSyncVar)
{
Gcm.Stop();
log.Info("Sent Gcm Notifications");
GcmStarted = false;
}
}
}
}
}
}
That happens when you try and reuse an instance of a service broker (eg: ApnsServiceBroker) which Stop() has been called on.
I'm guessing your Application_End is getting called at some point and Application_Start gets called again, but since PushBrokerSingleton.Apns is not null (it's a static field so it must live on even though the Application has stopped/started), it never gets recreated.
PushSharp is a hard thing to make work nicely with the ASP.NET pattern, some sort of service daemon would be better.
The main issue is that your app may be recycled or ended when you don't expect it to. Unrelated requests in the same app can take down your process, or your AppDomain may be torn down. If this happens and the brokers' Stop() calls can't end successfully, some queued messages could be lost. Here's a great article on some of the caveats: http://haacked.com/archive/2011/10/16/the-dangers-of-implementing-recurring-background-tasks-in-asp-net.aspx/ In practice, this may not be a big deal, and you can certainly mitigate parts of it, but keep it in mind.
Having said all that, I think a simple fix would be to create a new instance of PushBrokerSingleton.Apns and PushBrokerSingleton.Gcm in your Application_Start. This may cause other issues for you so I'm not sure if it's the right fix, but it will work around the issue that the broker is not meant to be reused after Stop() has been called.
I'm also going to consider adding some way to 'reset' the collection. I'm not sure if doing this automatically after .Stop() ends is a good idea, but I may look at adding a .Reset() or similar kind of method to achieve this. In any case, creating a new broker instance is perfectly acceptable for now.

How to split Akka.NET remoting solution to two solutions?

I have made 2 Akka.NET solutions in the hope of testing out Remoting on a simple hello world example, however, I keep getting a Disassociated exception when the communication attempt is made. I have reason to believe that this is because of the shared class Greet which should be a message that both systems should understand. Unfortunately, they don't. How can I fix this?
This is the code of the "Server" application:
namespace Shared
{
public class Greet
{
public string Who { get; set; }
public Greet(string who)
{
Who = who;
}
}
}
namespace AkkaTest
{
using Shared;
class GreeterActor : ReceiveActor
{
public GreeterActor()
{
Receive<Greet>(x => Console.WriteLine("Hello {0}", x.Who));
}
}
class Program
{
static void Main(string[] args)
{
var config = ConfigurationFactory.ParseString(#"
akka {
actor.provider = ""Akka.Remote.RemoteActorRefProvider, Akka.Remote""
remote {
helios.tcp {
port = 9099
hostname = 127.0.0.1
}
}
}
");
using (ActorSystem system = ActorSystem.Create("MyServer", config))
{
system.ActorOf<GreeterActor>("greeter");
Console.ReadLine();
system.Shutdown();
}
}
}
}
Here is the code for the client:
namespace Shared
{
public class Greet
{
public string Who { get; set; }
public Greet(string who)
{
Who = who;
}
}
}
namespace AkkaTest
{
using Shared;
class Program
{
static void Main(string[] args)
{
var config = ConfigurationFactory.ParseString(#"
akka {
actor.provider = ""Akka.Remote.RemoteActorRefProvider, Akka.Remote""
remote {
helios.tcp {
port = 9090
hostname = 127.0.0.1
}
}
}
");
using (var system = ActorSystem.Create("MyClient", config))
{
//get a reference to the remote actor
var greeter = system
.ActorSelection("akka.tcp://MyServer#127.0.0.1:9099/user/greeter");
//send a message to the remote actor
greeter.Tell(new Greet("Roger"));
Console.ReadLine();
}
}
}
}
EDIT: Putting both client and server in the same solution but different projects, and the GreetingActor and Greet in a shared projects fixes the issues. However, I would like to have completely separate solutions.
If you are using Greet messages on both sides, you need to provide some way do share this message schema between them. Usually this is done as a separate project shared between other projects or solutions.
While default Akka.NET serializer uses fully qualified type name with assembly to serialize/deserialize messages, it's also version tolerant - you can modify message schema and gradually update it's assembly node by node.
Other option is to use custom serializer. This way you'll be able to determine by yourself, how message will be serialized/deserialized on both ends. You can read more about this topic here.

Unknown command error when using multithread to set redis

I am using the ServiceStack.Redis C# client to talk to Redis.
With few request everything is ok, but when I get LoadRunner to request it or use multi-threading to make requests, I get some errors that say I am using the wrong command.
I check the errors, and it seems that it cut off the command, or it mess up.
Here is my code, very simple. Has anyone come across this problem? The errors happen when I call the Push method using multi-threading.
public class ImpresstionQueueService : IQueueService<InsertImpressionRequest>
{
private string _queueName;
private string _host;
private static IRedisClient redisClient = new RedisClient(ConfigHost);
private static string ConfigHost
{
get
{
return ConfigurationManager.AppSettings.Get("redis_host");
}
}
private string Host
{
get
{
if (!string.IsNullOrEmpty(_host))
return _host;
else
{
return ConfigurationManager.AppSettings.Get("redis_host");
}
}
}
public ImpresstionQueueService(string queue_name)
{
this._queueName = queue_name;
}
public ImpresstionQueueService(string host, string queu_name)
{
this._queueName = queu_name;
this._host = host;
}
#region IQueueService<InsertImpressionRequest> Members
class testData
{
}
public int Push(InsertImpressionRequest value)
{
try
{
//using (var redisClient = new RedisClient(this.Host))
{
//ser
string ser_value = TypeSerializer.SerializeToString<InsertImpressionRequest>(value);
//push
redisClient.AddItemToList(this._queueName, ser_value);//here will be error
}
}
catch (Exception ex)
{
HLogger.GetLogger("RedisLogger").Error(ex.Message + ex.StackTrace);
}
//throw new NotImplementedException();
return 1;
}
public InsertImpressionRequest Pop()
{
InsertImpressionRequest request = null;
//using (var redisClient = new RedisClient(this.Host))
{
string pop_string_value = redisClient.PopItemFromList(this._queueName);
//deseri
if (pop_string_value != null)
{
request = TypeSerializer.DeserializeFromString<InsertImpressionRequest>(pop_string_value);
}
}
return request;
}
#endregion
}
You are probably using the same Redis connection simultaneously from multiple threads. Both threads could possibly send commands or wait for replies at the same time. When this happens, one thread receives data intended for the other thread. This causes your error.
If you use one Redis client per thread (instead of one client per ImpresstionQueueService), each thread can send commands at the same time without interfering with each other.
Alternatively, you can create a client just for the single request (which you commented out just above the error location). The disadvantage of this alternative is the overhead of a new connection every time (which might be large or small or unnoticeable).

Categories