In a spring boot microservice, I'm having a Set of Wrapper Objects in my service class. This set represents subscribers, where the wrapper object includes all configurations needed by the subscriber's daos and http client, and this set is regularly synced to check for new subscribers or tenants that unsubscribed. 2 issues at least I could spot at the moment:
The issues seem very simple, but I have no idea where could the issue be, and if they actually are related and may cause more issues.
@Service
public class Service {
private final Configuration configuration;
private final ApplicationDao appDao;
private static final HashSet<ConfigurationWrapper> configurations = new HashSet<ConfigurationWrapper>();
@Autowired
public Service(Configuration configuration, ApplicationDao appDao) {
this.configuration = configuration;
this.appDao = appDao;
try {this.scheduledSubscriptionsSync();
} catch (IOException | HttpClientException e) {}
}
@Scheduled(cron = "0 0 0/1 * * ?")
private void scheduledSubscriptionsSync() throws IOException, HttpClientException {
List<User> subs = appDao.getAllSubscriptions();
addNewSubs(subs);
removeSubs(subs);
}
private void addNewSubs(List<User> subs) {
for (User sub : subs) {
Configuration config = configuration;
config.setUserName(sub.getName());
config.setPassword(sub.getPassword());
config.setTenantid(sub.getTenant());
ConfigurationWrapper newSubConfig = new ConfigurationWrapper(config, sub);
boolean isNewSubConfigAdded = configurations.add(newSubConfig);
if (isNewSubConfigAdded) {
LOGGER.info("New subscription found: {}", sub.toString());
int counter = 0;
for (ConfigurationWrapper configuration : Service.configurations) {
LOGGER.debug("!DEBUG! BOOTSTRAPSERVICE - PRINTING HASHSET AFTER ADD: " + configuration.toString() + ", POSITION: " + counter);
counter++;
}
}
}
}
private void removeSubs(List<User> subs) {
for (ConfigurationWrapper configuration : Service.configurations) {
if (!subs.contains(configuration.getSubscription())) {
configurations.remove(configuration);
LOGGER.info("Subscription removed: {}", configuration.getSubscription().toString());
}
}
}
public static HashSet<ConfigurationWrapper> getConfigurations() {
return configurations;
}
}
I tried changing the data structure of the set, between arrayLists and HashSets, and also making the Set static to avoid expired copies of the set, but still the issues remain.
public class ConfigurationWrapper {
private Configuration configuration;
private final HttpClient httpClient;
private final Daos daos;
private final Timestamps timestamps;
private final User subscription;
public ConfigurationWrapper(Configuration configuration, User subscription) {
this.configuration = configuration;
this.httpClient = new HttpClient(configuration, CredentialsProviderFactory.getConfigCredentials(configuration));
this.daos = new Daos(configuration, this.httpClient);
this.timestamps = new Timestamps();
this.subscription = subscription;
}
public Configuration getConfiguration() {
return configuration;
}
public HttpClient getHttpClient() {
return httpClient;
}
public Daos getDaos() {
return daos;
}
public Timestamps getTimestamps() {
return timestamps;
}
public User getSubscription() {
return subscription;
}
@Override
public String toString() {
return "ConfigurationWrapper [configuration="
+ configuration + ", subscription=" + subscription + "]";
}
@Override
public int hashCode() {
return Objects.hash(configuration, subscription);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ConfigurationWrapper other = (ConfigurationWrapper) obj;
return Objects.equals(configuration, other.configuration)
&& Objects.equals(subscription, other.subscription);
}
}
Problem solved!
For the first issue, I was using a single Configuration
object to create all ConfigurationWrapper
objects. This was causing all ConfigurationWrapper
objects to have the same Configuration
reference. To fix this issue, I had to create a new Configuration
object for each ConfigurationWrapper
.
For the second issue, the issue with unsubscribing tenants was related to the way I was comparing and removing them. When I remove a ConfigurationWrapper
from the set, I had to also update the iterator or use an iterator specifically designed for this purpose. I fixed it by using Iterator
instead of For
each.