Transient Error Occurer, deviceclient.sendmessage

試著忘記壹切 提交于 2019-12-12 03:12:13

问题


I have the following code which reads a temperature from a sensor on a raspberry pi.

The code is asynchronous, and if I remove ONLY the last line of the code, the one that sends the message, I never get the exception. I meant this line:

 await deviceClient.SendEventAsync(message);




 private async void InitializeSensors()
        {
            string calibrationData;
            //_periodicTimer.Dispose();
            // Inicializar el sensor bmp180
            try
            {
                _bmp180 = new Bmp180Sensor();
                await _bmp180.InitializeAsync();
                calibrationData = _bmp180.CalibrationData.ToString();   //Retorna una cadena que representa al objeto actual.
                if (_periodicTimer == null)
                {
                    _periodicTimer = new Timer(this.TimerCallback, null, 0, readingInterval);
                }
            }
            catch (Exception ex)
            {
                calibrationData = "Error de dispositivo! " + ex.Message;
            }

            var task = this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
            {
                //calibrationDataTextBlock.Text = "";
            });
        }

        public async void TimerCallback(object state)
        {
            string temperatureText;
            // Leer  datos del sensor
            try
            {
                var sensorData = await _bmp180.GetSensorDataAsync(Bmp180AccuracyMode.UltraHighResolution);
                temperatureText = sensorData.Temperature.ToString("");
                //pressureText = sensorData.Pressure.ToString("F2");
                temperatureText += "°C";
                //pressureText += "hPa - " + BitConverter.ToString(sensorData.UncompestatedPressure);
                var temperatureDataPoint = new
                {
                    deviceKey = deviceKey,
                    deviceName = deviceName,
                    temperatura = sensorData.Temperature,
                    fecha = DateTime.Now
                };
                var messageString = JsonConvert.SerializeObject(temperatureDataPoint);
                var message = new Microsoft.Azure.Devices.Client.Message(Encoding.ASCII.GetBytes(messageString));
                message.Properties["Ambiente"] = ambiente;

                ////temperatura.Text = temperatureText;
                await deviceClient.SendEventAsync(message);
            }
            catch (Exception ex)
            {
                temperatureText = "Sensor Error: " + ex.Message;
                //pressureText = "Sensor Error: " + ex.Message;
            }

            //// actualizaciones de la interfaz de usuario... deben ser invocados en el subproceso de interfaz de usuario
            var task = this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
            {
                temperatura.Text = temperatureText;
            });

        }

If I remove the lines, I can see that the sensor is working because the Textbox is updated with the real temmperature.

Only when I uncomment the sendmessage line I get the exception

How can I fix this?


回答1:


OK, looks like you have some thread-safety problem.

Per https://msdn.microsoft.com/en-us/library/microsoft.azure.devices.client.deviceclient.aspx, Any instance members (of DeviceClient) are not guaranteed to be thread safe.

So it is your(aka the developer) responsibility to take care of the thread-safety when using things like SendEventAsync.

In your case, when you kick off a timer, the framework will create worker threads each time the ticks elapsed, this could be an issue especially when the latency of

await deviceClient.SendEventAsync(message);

is undeterministic, so you might end up several working threads making the same SendEventAsync calls.

A quick and simple fix is to add an AutoResetEvent around this API call(locker does not agree with await), something like below,

autoResetEvent.WaitOne();
await deviceClient.SendEventAsync(eventMessage);
autoResetEvent.Set();

Do make this autoResetEvent global so that it's shared by all the worker threads.

PS: I see you're trying to read from the some Bmp180 sensor, you might want to make those calls thread-safe as well.

Let me know if it works for you.



来源:https://stackoverflow.com/questions/39736517/transient-error-occurer-deviceclient-sendmessage

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!