I have implemented an MQTT event listener like this:
@Service
@Slf4j
@RequiredArgsConstructor
public class SoilHumidityEventListener {
private final MqttClient mqttClient;
private final ObjectMapper objectMapper;
private final PlantService plantService;
@Value("${mqtt.soil_humidity_topic}")
private String soilHumidityTopic;
@Transactional
public void subscribe() throws MqttException {
mqttClient.subscribe(soilHumidityTopic, this::messageArrived);
}
@Transactional
public void messageArrived(String topic, MqttMessage message) {
try {
SoilHumidityDto soilHumidityDto =
objectMapper.readValue(message.toString(), SoilHumidityDto.class);
Plant plant = plantService.findById(soilHumidityDto.getPlantId());
SoilHumidity soilHumidity = SoilHumidity.fromDto(soilHumidityDto);
soilHumidity.setPlant(plant);
plant.getSoilHumidityList().add(soilHumidity);
plantService.save(plant);
} catch (Exception e) {
log.error("Error parsing and saving soil humidity message: {}", e.getMessage());
}
}
}
The method plantService.findById(...)
is also marked with @Transactional
. the subscribe method in SoilHumidityEventListener
is called in another service as bellow:
@Service
@RequiredArgsConstructor
@Slf4j
public class EventSubscriberService {
private final SoilHumidityEventListener soilHumidityEventListener;
@PostConstruct
@Transactional
public void initialize() {
try {
soilHumidityEventListener.subscribe();
} catch (MqttException e) {
log.error(e.getMessage());
}
}
}
The problem is that there is no active transaction in the messageArrived()
method. As a result I get a LazyInitializationException
when trying to update the soilHumidityList
of the plant
object. The quick fix to this problem is to load the soilHumidityList
eagerly. But I want to avoid this. Is there a way to keep the transaction open when handling MQTT messages?