use of alma.acs.nc.AcsEventSubscriber in project ACS by ACS-Community.
the class NCSubscriberAdminReuseTest method testNewAndOldNCsTogether.
/**
* TODO: Write a similar test with an old-style C++ Consumer,
* once we remove the deprecated Java NC Consumer.
*/
public void testNewAndOldNCsTogether() throws Exception {
List<Consumer> consumers = new ArrayList<Consumer>();
for (int i = 1; i <= 10; i++) {
// Create the maximum number of proxies per admin
// Also, per every NCSubscriber, create an old Consumer
AcsEventSubscriber[] subscribers = new AcsEventSubscriber[NCSubscriber.PROXIES_PER_ADMIN];
for (int j = 0; j != NCSubscriber.PROXIES_PER_ADMIN; j++) {
subscribers[j] = getContainerServices().createNotificationChannelSubscriber(CHANNEL_NAME, IDLEntity.class);
Consumer c = new Consumer(CHANNEL_NAME, getContainerServices());
consumers.add(c);
}
assertEquals(i * (1 + NCSubscriber.PROXIES_PER_ADMIN), channel.get_all_consumeradmins().length);
}
// Now, let's examine the consumer admins, and see whether they are shared or not
int sharedAdmins = 0;
int lonelyAdmins = 0;
for (int adminID : channel.get_all_consumeradmins()) {
ConsumerAdmin admin = channel.get_consumeradmin(adminID);
boolean isSharedAdmin = false;
for (int proxyID : admin.push_suppliers()) {
ProxySupplier proxy = admin.get_proxy_supplier(proxyID);
if (ProxyType.PUSH_ANY.equals(proxy.MyType())) {
isSharedAdmin = true;
break;
}
}
if (isSharedAdmin) {
assertEquals(NCSubscriber.PROXIES_PER_ADMIN, admin.push_suppliers().length - 1);
sharedAdmins++;
} else
lonelyAdmins++;
}
assertEquals(10, sharedAdmins);
assertEquals(10 * NCSubscriber.PROXIES_PER_ADMIN, lonelyAdmins);
// Manually free these old filthy consumers
for (Consumer c : consumers) c.disconnect();
}
use of alma.acs.nc.AcsEventSubscriber in project ACS by ACS-Community.
the class InMemoryNcTest method testConcurrentUse.
/**
* Heavy-duty test to check for concurrency problems
* and to do basic verification of throughput performance (which is limited by having a single receiver).
* <p>
* We want to test also the asynchronous event processing in AcsEventSubscriberImplBase,
* but then must throttle the publishers so that the subscribers don't lose data.
* Still we want the publishers to fire fast enough so that the subscribers get stressed at times.
* This is achieved by letting the publishers fire batches of events at maximum speed,
* but then wait for the entire batch to be received by the registered receiver class.
* These pulses of events are calculated to at most fill up the subscriber queue completely,
* which means that we may get warnings about slow receivers ("More events came in from the NC than the receiver processed"),
* but still no data should be lost ("numEventsDiscarded=0").
*/
@Test
public void testConcurrentUse() throws Exception {
InMemoryNcFake nc = new InMemoryNcFake(services, "myTestChannel");
final int numEventsPerPublisher = 2000;
final int numPublishers = 5;
final int numEventsPublishedTotal = numEventsPerPublisher * numPublishers;
final int numActiveSubscribers = 5;
final int numInactiveSubscribers = 2;
final int numEventsToReceiveTotal = numEventsPublishedTotal * numActiveSubscribers;
final int eventBatchSize = Math.min(numEventsPerPublisher, AcsEventSubscriberImplBase.EVENT_QUEUE_CAPACITY / numPublishers);
assertThat("Current choice of test parameters leads to illegal batch size.", eventBatchSize, greaterThanOrEqualTo(1));
final int numEventsToReceivePerBatch = eventBatchSize * numPublishers * numActiveSubscribers;
logger.info("Will use " + numPublishers + " publishers to each publish " + numEventsPerPublisher + " events (in batches of " + eventBatchSize + " each synchronized with the receivers), and " + numActiveSubscribers + " subscribers for these events. In addition we have " + numInactiveSubscribers + " subscribers that should not receive these events.");
StopWatch sw = new StopWatch(logger);
// set up publishers (unlike above we do it before the subscribers, just to make sure that works as well)
List<InMemoryPublisher<TestEventType1>> publishers = new ArrayList<InMemoryPublisher<TestEventType1>>(numPublishers);
for (int i = 1; i <= numPublishers; i++) {
AcsEventPublisher<TestEventType1> pub = nc.createPublisher("myTestPublisher" + i, TestEventType1.class);
publishers.add((InMemoryPublisher) pub);
}
sw.logLapTime("create " + numPublishers + " publishers");
// set up subscribers
final SyncingEventCollector eventCollector = new SyncingEventCollector(numPublishers, numEventsToReceivePerBatch, numEventsToReceiveTotal);
TestEventReceiver1 sharedReceiver = new TestEventReceiver1(eventCollector);
List<AcsEventSubscriber<?>> subscribers = new ArrayList<AcsEventSubscriber<?>>(numActiveSubscribers);
for (int i = 1; i <= numActiveSubscribers; i++) {
AcsEventSubscriber<TestEventType1> sub = nc.createSubscriber("myTestSubscriber" + i, TestEventType1.class);
subscribers.add(sub);
sub.addSubscription(sharedReceiver);
sub.startReceivingEvents();
}
for (int i = 1; i <= numInactiveSubscribers; i++) {
if (i % 2 == 0) {
AcsEventSubscriber<TestEventType1> sub = nc.createSubscriber("myInactiveTestSubscriber" + i, TestEventType1.class);
subscribers.add(sub);
sub.addSubscription(sharedReceiver);
// do not call sub.startReceivingEvents() for this inactive subscriber
} else {
AcsEventSubscriber<TestEventType2> sub = nc.createSubscriber("myTestSubscriber" + i, TestEventType2.class);
subscribers.add(sub);
sub.startReceivingEvents();
}
}
sw.logLapTime("create " + (numActiveSubscribers + numInactiveSubscribers) + " subscribers");
// Publish and receive "event1" as specified above
final TestEventType1 event1 = new TestEventType1();
final List<Throwable> asyncThrowables = Collections.synchronizedList(new ArrayList<Throwable>());
final CountDownLatch synchOnPublishers = new CountDownLatch(numPublishers);
class PublisherRunnable implements Runnable {
private final InMemoryPublisher<TestEventType1> publisher;
PublisherRunnable(InMemoryPublisher<TestEventType1> publisher) {
this.publisher = publisher;
}
@Override
public void run() {
for (int i = 1; i <= numEventsPerPublisher; i++) {
try {
publisher.publishEvent(event1);
if (i % eventBatchSize == 0) {
awaitEventReception();
}
} catch (Exception ex) {
asyncThrowables.add(ex);
}
}
// test getEventCount()
if (publisher.getEventCount() != numEventsPerPublisher) {
asyncThrowables.add(new Exception("Published only " + publisher.getEventCount() + " events when " + numEventsPerPublisher + " were expected."));
}
try {
publisher.disconnect();
} catch (AcsJIllegalStateEventEx ex) {
asyncThrowables.add(ex);
}
// the last batch may be smaller than eventBatchSize, so that we need to sync on their reception with this extra call
awaitEventReception();
synchOnPublishers.countDown();
}
private void awaitEventReception() {
try {
// StopWatch swWait = new StopWatch(logger);
eventCollector.awaitEventBatchReception();
// logger.fine("Publisher in thread " + Thread.currentThread().getName() + " returned from awaitEventBatchReception() in " + swWait.getLapTimeMillis() + " ms.");
} catch (Exception ex) {
asyncThrowables.add(ex);
}
}
}
// let each publisher fire its events from a separate thread
for (InMemoryPublisher<TestEventType1> publisher : publishers) {
services.getThreadFactory().newThread(new PublisherRunnable(publisher)).start();
}
// wait for publishers to fire all events (which includes already their waiting for event reception)
assertThat(synchOnPublishers.await(1, TimeUnit.MINUTES), is(true));
// verify results
assertThat(asyncThrowables, is(empty()));
assertThat(eventCollector.getNumEventsReceivedTotal(), equalTo((long) numEventsToReceiveTotal));
sw.logLapTime("publish " + numEventsPublishedTotal + " and receive " + numEventsToReceiveTotal + " events");
}
use of alma.acs.nc.AcsEventSubscriber in project ACS by ACS-Community.
the class ContainerServicesImpl method createNotificationChannelSubscriber.
/**
* @TODO: once we support notification over other frameworks, check that configuration
* and instantiate some class other than NCSubscriber.
* @see alma.acs.container.ContainerServices#createNotificationChannelSubscriber(String, String)
*/
@Override
public <T> AcsEventSubscriber<T> createNotificationChannelSubscriber(String channelName, String channelNotifyServiceDomainName, Class<T> eventType) throws AcsJContainerServicesEx {
AcsEventSubscriber<T> subscriber = null;
try {
Object[] args = new Object[] { channelName, channelNotifyServiceDomainName, this, getNameService(), m_clientName, eventType };
@SuppressWarnings("unchecked") Class<AcsEventSubscriber<T>> clazz = (Class<AcsEventSubscriber<T>>) Class.forName(CLASSNAME_NC_SUBSCRIBER);
Constructor<AcsEventSubscriber<T>> constructor = clazz.getConstructor(String.class, String.class, ContainerServicesBase.class, NamingContext.class, String.class, Class.class);
subscriber = constructor.newInstance(args);
} catch (ClassNotFoundException e) {
// TODO: maybe we could prevent future NCSubscriber creation tries, since the class isn't and will not be loaded
// The same applies for the next "catch" block
m_logger.log(AcsLogLevel.ERROR, "Cannot create NC subscriber because the 'NCSubscriber' class is not present in the classpath", e);
AcsJContainerServicesEx ex = new AcsJContainerServicesEx(e);
ex.setContextInfo("'" + CLASSNAME_NC_SUBSCRIBER + "' class not present in the classpath");
throw ex;
} catch (ClassCastException e) {
m_logger.log(AcsLogLevel.ERROR, "Cannot create NC subscriber because loaded class is not of type 'AcsEventSubscriber", e);
AcsJContainerServicesEx ex = new AcsJContainerServicesEx(e);
ex.setContextInfo("'" + CLASSNAME_NC_SUBSCRIBER + "' class does not extend 'AcsEventSubscriber'");
throw ex;
} catch (Throwable e) {
if (e instanceof InvocationTargetException) {
// ctor ex
e = e.getCause();
}
m_logger.log(AcsLogLevel.ERROR, "Unexpected error while creating new AcsEventSubscriber object", e);
AcsJContainerServicesEx ex = new AcsJContainerServicesEx(e);
throw ex;
}
m_subscribers.put((channelNotifyServiceDomainName == null ? "" : channelNotifyServiceDomainName) + "/" + channelName, subscriber);
return subscriber;
}
use of alma.acs.nc.AcsEventSubscriber in project ACS by ACS-Community.
the class NCSubscriberAdminReuseTest method runConcurrentSubscribersCreation.
private void runConcurrentSubscribersCreation(int numRealSubscribersDefinedTotal) throws Exception {
m_logger.info("Setting up " + numRealSubscribersDefinedTotal + " concurrent subscriber creations...");
final List<AcsEventSubscriber<IDLEntity>> subscribers = Collections.synchronizedList(new ArrayList<AcsEventSubscriber<IDLEntity>>());
// Create all the tasks first
ThreadBurstExecutorService executor = new ThreadBurstExecutorService(getContainerServices().getThreadFactory());
for (int i = 0; i < numRealSubscribersDefinedTotal; i++) {
Runnable r = new Runnable() {
public void run() {
try {
// create subscriber, and add it to the list
subscribers.add(getContainerServices().createNotificationChannelSubscriber(CHANNEL_NAME, IDLEntity.class));
} catch (Exception e) {
m_logger.log(Level.WARNING, "Failed to create a subscriber.", e);
}
}
};
try {
executor.submit(r, 100, TimeUnit.SECONDS);
} catch (InterruptedException e1) {
fail("Failed to submit the subscriber creator thread to the executor service");
}
}
// and now run'em all at the same time! (concurrently)
m_logger.info("Will run " + numRealSubscribersDefinedTotal + " concurrent subscriber creations...");
try {
boolean startOK = executor.executeAllAndWait(100, TimeUnit.SECONDS);
assertTrue("Not all subscribers started within the alotted 100 seconds window.", startOK);
} catch (InterruptedException e) {
fail("Got InterruptedException while running all my threads");
}
// After all the show, we should have all requested subscribers in the local list
assertEquals(numRealSubscribersDefinedTotal, subscribers.size());
m_logger.info("Successfully created " + numRealSubscribersDefinedTotal + " subscribers semi-concurrently. Will now check their NC admin links...");
// Check if these subscribers are distributed correctly over several admin objects,
// allowing for some overbooking due to concurrent requests (see comment about concurrency in c'tor of NCSubscriber)
final int allowedAdminOverbooking = 2;
int numRealSubscribersFoundTotal = 0;
int[] adminIDs = channel.get_all_consumeradmins();
for (int i = 0; i < adminIDs.length; i++) {
int adminID = adminIDs[i];
String msgBase = "Subscriber admin #" + (i + 1) + " (of " + adminIDs.length + ") ";
try {
int subs = channel.get_consumeradmin(adminID).push_suppliers().length;
// minus 1 for the 'management' subscriber
int numRealSubscribersThisAdmin = subs - 1;
m_logger.info(msgBase + "has " + numRealSubscribersThisAdmin + " proxy objects (subscribers) attached.");
if (i < adminIDs.length - 1) {
// This is not the last of the admin objects. It should be filled to the brim with proxies.
assertThat(msgBase + "should be full with " + NCSubscriber.PROXIES_PER_ADMIN + " proxies.", numRealSubscribersThisAdmin, greaterThanOrEqualTo(NCSubscriber.PROXIES_PER_ADMIN));
assertThat(msgBase + "has more proxies than allowed by 'allowedAdminOverbooking'=" + allowedAdminOverbooking + ", which may be OK.", numRealSubscribersThisAdmin, lessThanOrEqualTo(NCSubscriber.PROXIES_PER_ADMIN + allowedAdminOverbooking));
} else {
// We should be at the last of the admin objects, which may be only partially filled
assertThat(msgBase + "has more proxies than allowed by 'allowedAdminOverbooking'=" + allowedAdminOverbooking + ", which may be OK.", numRealSubscribersThisAdmin, lessThanOrEqualTo(NCSubscriber.PROXIES_PER_ADMIN + allowedAdminOverbooking));
assertThat(msgBase + "should contain all remaining proxies.", numRealSubscribersThisAdmin, equalTo(numRealSubscribersDefinedTotal - numRealSubscribersFoundTotal));
}
numRealSubscribersFoundTotal += numRealSubscribersThisAdmin;
} catch (AdminNotFound ex) {
fail("Can't get information about consumer admin #" + (i + 1) + " (ID=" + adminID + "): " + ex.toString());
}
}
destroyConsumers();
}
Aggregations