Regarding drawbacks in failure, this is how activeMQ works.
If the "failure/bad acknowledge" happens on the business logic layer then you should use transactions
Warning Not a valid code (pradigm)
// at your Listener
public void onMessage(Message message)
{
if (isValid(message))
{
connection.ack();
commit();
return;
}
rollback();
}
Regarding the message throttling and persistence the following configuration of destination policy will assist you.
<destinationPolicy>
<policyMap>
<policyEntries>
<policyEntry topic=">" producerFlowControl="true" memoryLimit="10mb">
<pendingSubscriberPolicy>
<vmCursor />
</pendingSubscriberPolicy>
</policyEntry>
<policyEntry queue=">" producerFlowControl="true" memoryLimit="10mb">
<pendingQueuePolicy>
<vmQueueCursor/>
</pendingQueuePolicy>
</policyEntry>
</policyEntries>
</policyMap>
</destinationPolicy>
IMHO I would also use MySQL for this kind of persistence
<persistenceAdapter>
<jdbcPersistenceAdapter dataDirectory="${activemq.base}/data" dataSource="#mysql-ds"/>
</persistenceAdapter>
Also I advise you to use Camel to configure your throttler as you wish.