[JBoss AS7 Development] - Asynchronous results from executing a deployment plan
by Brian Stansberry
Brian Stansberry [http://community.jboss.org/people/bstansberry%40jboss.com] created the discussion
"Asynchronous results from executing a deployment plan"
To view the discussion, visit: http://community.jboss.org/message/560731#560731
--------------------------------------------------------------
One of the main things I've been struggling with when implementing deployments is how to provide information to the caller on the results of executing a deployment plan. In the deployment API discussed at https://community.jboss.org/thread/155937?tstart=0 https://community.jboss.org/thread/155937?tstart=0 the StandaloneDeploymentPlan.execute(DeploymentPlan) method returns a DeploymentPlanResult object. That's straightforward enough; what's interesting is making getting the details of those results asynchronous.
There are two facets of the asynchronous problem:
1) As discussed on https://community.jboss.org/thread/154922?tstart=0 https://community.jboss.org/thread/154922?tstart=0 there's a desire to immediately return control to the user and let them come back later to check for results. I'm looking at doing that by encapsulating the result details in a Future and executing the plan on another thread. Simple enough.
2) Even if we made the caller always block waiting for the results, it's still complex, because the deployment process itself is asynchronous. More specifically, installing the services generated from the deployment is multi-threaded -- MSC breaks down all service start/stop work into tasks that are executed by threads from an Executor. So, the thread that's executing the deployment plan and trying to assemble the results can't just invoked BatchBuilder.install() and assume everything is done when that call return. After install() returns that thread needs to find a way to detect what all the services associated with the deployment are and monitor their status as other threads actually register and start them.
The 2) issue is the focus of the rest of this post.
The approach I'm looking at using is making use of the o.j.as.deployment.DeploymentService class to facilitate this. Currently that class is being used as a sort of empty placeholder on which all other services associated with a deployment depend. Telling the MSC to stop/remove a DeploymentService instance is thus a simple way to trigger removal of all the associated services. This is how undeploy and rollback of a failed deployment are working.
What I'm looking at doing is giving DeploymentService a richer set of behaviors. Basically giving it the ability to track what the services are that were associated with a deployment and an API that lets callers find out about those services. Users interested in finding out details of the results of executing a deployment plan could indirectly call into that API.
The DeploymentService learns about the services associated with a deployment by getting callbacks from a ServiceListener that is registered with the sub-batch that's actually doing the deployment:
public void activate(final ServiceActivatorContext context) {
.......
final BatchBuilder batchBuilder = context.getBatchBuilder();
// Create deployment service
final ServiceName deploymentServiceName = DeploymentService.SERVICE_NAME.append(deploymentName);
DeploymentService deploymentService = new DeploymentService();
batchBuilder.addService(deploymentServiceName, deploymentService);
// Create a sub-batch for this deployment
final BatchBuilder deploymentSubBatch = batchBuilder.subBatchBuilder();
// Setup a batch level dependency on deployment service
deploymentSubBatch.addDependency(deploymentServiceName);
// Let deploymentService listen to services in the subbatch
deploymentSubBatch.addListener(deploymentService.getDependentStartupListener());
// Add a deployment failure listener to the batch
deploymentSubBatch.addListener(new DeploymentFailureListener(deploymentServiceName));
..... go on and create deployment unit and pass it to deployer chain
Important (i.e. new) bit is in bold.
The DeploymentService (and the listener class used above) look like this:
public class DeploymentService implements Service<DeploymentService> {
public static final ServiceName SERVICE_NAME = ServiceName.JBOSS.append("deployment");
private static Logger logger = Logger.getLogger("org.jboss.as.deployment");
private final Map<ServiceName, ServiceController<?>> dependents = new HashMap<ServiceName, ServiceController<?>>();
/** Dependent services that have not yet reached a terminal state in their initial startup (UP, FAILED, DOWN, REMOVED) */
private final Set<ServiceName> incompleteDependents = new HashSet<ServiceName>();
private final Lock lock = new ReentrantLock();
private final Condition startupCondition = lock.newCondition();
private final Condition stoppedCondition = lock.newCondition();
/** Whether start() has been invoked since initialization or the last stop() call */
private boolean started = false;
/** Whether stop() has been invoked since initialization or the last start() call */
private boolean stopped = false;
/**
* Start the deployment. This will re-mount the deployment root if service is restarted.
*
* @param context The start context
* @throws StartException if any problems occur
*/
public void start(StartContext context) throws StartException {
lock.lock();
try {
started = true;
stopped = false;
startupCondition.notifyAll();
}
finally {
lock.unlock();
}
}
/**
* Stop the deployment. This will close the virtual file mount.
*
* @param context The stop context
*/
public void stop(StopContext context) {
lock.lock();
try {
stopped = true;
started = false;
stoppedCondition.notifyAll();
}
finally {
lock.unlock();
}
}
/** {@inheritDoc} **/
public DeploymentService getValue() throws IllegalStateException {
return this;
}
/**
* Blocks until all services associated with this deployment have
* completed startup (not necessarily successfully).
*
* @throws InterruptedException
*/
public void awaitDependentStartup() throws InterruptedException {
lock.lock();
try {
while (!stopped && (!started || incompleteDependents.size() > 0)) {
if (onlyNeverMode()) {
break;
}
startupCondition.await();
}
}
finally {
lock.unlock();
}
}
/**
* Blocks until all services associated with this deployment have
* completed startup (not necessarily successfully) or the specified
* timeout occurs.
*
* @throws InterruptedException
*/
public void awaitDependentStartup(long timeout, TimeUnit timeUnit) throws InterruptedException {
lock.lock();
try {
while (!stopped && (!started || incompleteDependents.size() > 0)) {
if (onlyNeverMode()) {
break;
}
startupCondition.await(timeout, timeUnit);
}
}
finally {
lock.unlock();
}
}
/**
* Blocks until this service is stopped.
*
* @throws InterruptedException
*/
public void awaitStop() throws InterruptedException {
lock.lock();
try {
while (!stopped) {
stoppedCondition.await();
}
}
finally {
lock.unlock();
}
}
/**
* Blocks until this service is stopped or the specified
* timeout occurs.
*
* @throws InterruptedException
*/
public void awaitStop(long timeout, TimeUnit timeUnit) throws InterruptedException {
lock.lock();
try {
while (!stopped) {
stoppedCondition.await(timeout, timeUnit);
}
}
finally {
lock.unlock();
}
}
/**
* Gets any exceptions that occurred during start of the services that
* are associated with this deployment.
*
* @return the exceptions keyed by the name of the service. Will not be <code>null</code>
*/
public Map<ServiceName, StartException> getDependentStartupExceptions() {
lock.lock();
try {
Map<ServiceName, StartException> result = new HashMap<ServiceName, StartException>();
for (Map.Entry<ServiceName, ServiceController<?>> entry : dependents.entrySet()) {
StartException se = entry.getValue().getStartException();
if (se != null)
result.put(entry.getKey(), se);
}
return result;
}
finally {
lock.unlock();
}
}
/**
* Gets the {@link ServiceController.State state} of the services that
* are associated with this deployment.
*
* @return the services and their current state. Will not be <code>null</code>
*/
public Map<ServiceName, ServiceController.State> getDependentStates() {
lock.lock();
try {
Map<ServiceName, ServiceController.State> result = new HashMap<ServiceName, ServiceController.State>(dependents.size());
for (Map.Entry<ServiceName, ServiceController<?>> entry : dependents.entrySet()) {
result.put(entry.getKey(), entry.getValue().getState());
}
return result;
}
finally {
lock.unlock();
}
}
/**
* Gets a {@link ServiceListener} that can track startup events for
* services associated with the deployment this service represents. This
* listener should
* be associated with a {@link BatchBuilder#subBatchBuilder() sub-batch}
* of this services batch that encapsulates the creation of services that
* are associated with the deployment.
*
* @return the service listener
*/
public ServiceListener<Object> getDependentStartupListener() {
return new DependentServiceListener();
}
/** Checks whether all incomplete dependents are Mode.NEVER. Must be called with the lock held */
private boolean onlyNeverMode() {
int ever = incompleteDependents.size();
for (ServiceName name : incompleteDependents) {
ServiceController<?> controller = dependents.get(name);
if (controller == null || controller.getMode() == Mode.NEVER)
ever--;
}
return ever == 0;
}
private class DependentServiceListener extends AbstractServiceListener<Object> {
/**
* This will be called for all dependent services before the
* BatchBuilder.install() call returns. So at that point we know what
* the dependent services are; other threads will invoke the other
* callbacks are services are started.
*/
@Override
public void listenerAdded(ServiceController<? extends Object> controller) {
lock.lock();
try {
dependents.put(controller.getName(), controller);
incompleteDependents.add(controller.getName());
}
finally {
lock.unlock();
}
}
@Override
public void serviceFailed(ServiceController<? extends Object> controller, StartException reason) {
lock.lock();
try {
incompleteDependents.remove(controller.getName());
startupCondition.notifyAll();
}
finally {
lock.unlock();
}
}
@Override
public void serviceRemoved(ServiceController<? extends Object> controller) {
lock.lock();
try {
incompleteDependents.remove(controller.getName());
startupCondition.notifyAll();
}
finally {
lock.unlock();
}
}
@Override
public void serviceStopped(ServiceController<? extends Object> controller) {
lock.lock();
try {
incompleteDependents.remove(controller.getName());
startupCondition.notifyAll();
}
finally {
lock.unlock();
}
}
}
}
Besides the listener, the other interesting bit in the above are the awaitXXX methods. Those are what allow a caller that actually wants to find out what happened with a deployment to block until the asynchronous MSC tasks complete.
The awaitStop() methods are straightforward enough.
The awaitDependentStartup() implementation is more subtle. It depends on the fact that the listener's listenerAdded() method should be invoked passing in any services associated with the deployment before the BatchBuilder.install() method returns. My understanding of how MSC works tells me this is the case -- all listeners associated with a batch are passed to ServiceBuilderImpl and the listenerAdded method is invoked as part of ServiceBuilderImpl.doCreate(). This is all done as part of executing BatchBuilder.install(). This seems like a logical and necessary part of the BatchBuilder.install() contract; it would be good if it were documented as such.
There is a subtle race here though. In BatchBuilder.install() the DeploymentService itself could have all dependencies satisfied and tasks executed by another thread to start it before the thread executing install() processes the dependent services and calls listenerAdded(). :( If a caller invoked awaitDependentStartup() during this window, it would return even though the dependent services are not yet started. I'm dealing with that by having the thread that executes BatchBuilder.install() not expose DeploymentService.awaitDependentStartup() to any calling threads until the install() method returns.
--------------------------------------------------------------
Reply to this message by going to Community
[http://community.jboss.org/message/560731#560731]
Start a new discussion in JBoss AS7 Development at Community
[http://community.jboss.org/choose-container!input.jspa?contentType=1&cont...]
13 years, 8 months
[JBoss AS7 Development] - XML File Deployments
by Jason Greene
Jason Greene [http://community.jboss.org/people/jason.greene%40jboss.com] created the discussion
"XML File Deployments"
To view the discussion, visit: http://community.jboss.org/message/560307#560307
--------------------------------------------------------------
In past discussions it seemed unlikely that we would support XML deployments. This was for the following reasons:
1. The file would have to specify module configuration inline for it to even work (there is no more flat classpath in AS7) [and be polluted with other various AS internal info]
2. Configuration is no longer a "deployable" notion. The domain config contains all admin focused configs and supports runtime updates. This includes which subsystems are available
3. Code must be associated with it to really be worth being a deployment, so why not just bundle the code with the deployment? Even some kind of templating/scripting would likely be better represented as multiple files.
4. Everything you can do with an XML file can be done with an archive containing the XML file
Is there a strong case for it that was missed?
--------------------------------------------------------------
Reply to this message by going to Community
[http://community.jboss.org/message/560307#560307]
Start a new discussion in JBoss AS7 Development at Community
[http://community.jboss.org/choose-container!input.jspa?contentType=1&cont...]
13 years, 8 months
[jBPM Development] - task-node node replacement in jbpm 4
by ashutosh deora
ashutosh deora [http://community.jboss.org/people/ashutoshd] created the discussion
"task-node node replacement in jbpm 4"
To view the discussion, visit: http://community.jboss.org/message/560707#560707
--------------------------------------------------------------
i have a tag like the below mentioned
<task-node name="HBA Parking Mobility" async="true">
<task name="HBA Parking Mobility" description="HBA Parking Mobility">
<assignment handler="exienta.bpm.drools.SimpleRuleBasedAssignmentHandler"
class="exienta.bpm.drools.SimpleRuleBasedAssignmentHandler">
<workingMemoryName>taskAssignmentWorkingMemory
</workingMemoryName>
</assignment>
</task>
<transition to="Parking Mobility fertig"></transition>
</task-node>
*<task-node name="xxxxxxxx" async="true">*
** *<task name="*xxxxxxxx*" description="*xxxxxxxx*">*
** *<assignment handler="java.class"*
** *class="class">*
** *<workingMemoryName>*xxxxxxxx**
** *</workingMemoryName>*
** *</assignment>*
** *</task>*
** *<transition to="*xxxxxxxx*"></transition>*
** *</task-node>*
*this is a process written in jbpm 3.2.2*
*how the same will be written in jbpm 4.3*
*please suggest with possible solutions*
*its urgent*
--------------------------------------------------------------
Reply to this message by going to Community
[http://community.jboss.org/message/560707#560707]
Start a new discussion in jBPM Development at Community
[http://community.jboss.org/choose-container!input.jspa?contentType=1&cont...]
13 years, 8 months
[jBPM Development] - ObjectNotFoundException in JBPM process
by Abdul Rahman Kunhi Ahamed
Abdul Rahman Kunhi Ahamed [http://community.jboss.org/people/abdulrahman] created the discussion
"ObjectNotFoundException in JBPM process"
To view the discussion, visit: http://community.jboss.org/message/560989#560989
--------------------------------------------------------------
Hi Guys,
At times when JBPM tries to trigger a *timed state* it throws a hibernate exception.
The exception is logged in the table JBPM4_JOB as shown below
org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [org.jbpm.pvm.internal.model.ExecutionImpl#306479]
at org.hibernate.impl.SessionFactoryImpl$2.handleEntityNotFound(SessionFactoryImpl.java:409)
at org.hibernate.proxy.AbstractLazyInitializer.checkTargetState(AbstractLazyInitializer.java:108)
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:97)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:140)
at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:190)
at org.jbpm.pvm.internal.model.ExecutionImpl_$$_javassist_5.toString(ExecutionImpl_$$_javassist_5.java)
at java.lang.String.valueOf(String.java:2827)
at java.lang.StringBuilder.append(StringBuilder.java:115)
at org.jbpm.pvm.internal.job.TimerImpl.execute(TimerImpl.java:119)
at org.jbpm.pvm.internal.job.TimerImpl.execute(TimerImpl.java:1)
at org.jbpm.pvm.internal.cmd.ExecuteJobCmd.execute(ExecuteJobCmd.java:76)
at org.jbpm.pvm.internal.cmd.ExecuteJobCmd.execute(ExecuteJobCmd.java:1)
at org.jbpm.pvm.internal.svc.DefaultCommandService.execute(DefaultCommandService.java:42)
at org.jbpm.pvm.internal.tx.StandardTransactionInterceptor.execute(StandardTransactionInterceptor.java:54)
at org.jbpm.pvm.internal.svc.EnvironmentInterceptor.executeInNewEnvironment(EnvironmentInterceptor.java:53)
at org.jbpm.pvm.internal.svc.EnvironmentInterceptor.execute(EnvironmentInterceptor.java:40)
at org.jbpm.pvm.internal.svc.RetryInterceptor.execute(RetryInterceptor.java:55)
at org.jbpm.pvm.internal.svc.SkipInterceptor.execute(SkipInterceptor.java:43)
at org.jbpm.pvm.internal.jobexecutor.JobParcel.run(JobParcel.java:48)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:885)
The state of the job is changed to ‘error’.
Upon checking the JBPM4_EXECUTION there is no entry in the table releated to the job which the jbpm tries to execute.
Also this scenario is hard to recreate as we are not sure why the row is not inserted or getting deleted in the JBPM4_EXECUTION table.
Any help will be greatly appreciated.
I am using Weblogic 10.3 with JSF,SEAM and JBPM 4.2 and Oracle as the db
Thanks in advance
Abdul
--------------------------------------------------------------
Reply to this message by going to Community
[http://community.jboss.org/message/560989#560989]
Start a new discussion in jBPM Development at Community
[http://community.jboss.org/choose-container!input.jspa?contentType=1&cont...]
13 years, 8 months
[JBoss AS7 Development] - Re: Steps in building up the domain management architecture
by John Bailey
John Bailey [http://community.jboss.org/people/johnbailey] created the discussion
"Re: Steps in building up the domain management architecture"
To view the discussion, visit: http://community.jboss.org/message/560721#560721
--------------------------------------------------------------
The process I have laid out for booting the domain controller is as follows:
1. Server manager boots and parses the host.xml
2. If the domain controller local config exists it tells the process manager to launch the DC
3. The DC boots, parses the domain, opens its interface for SM communication
4. The SM waits for the local DC to finish booting and connects to the DC
5. Once connected the SM registers itself with the DC
6. Once the SM is registered the DC passes the latest domain to the SM
7. Once the SM gets the updated domain, it launches the servers
Does this make sense? The question I have is whether to parse the domain in the SM and pass it to the local DC, or only have the DC parse the domain? I am leaning to the DC parsing the domain since it is in charge of it. The only issue is there is a little bit of a delay in the SM starting the servers. This should be a fairly small delay, but it is a delay. All the other (remote) SM processes will have to wait for the DC anyway, so it seems better to me to have the local case act as much like the remote case as possible.
--------------------------------------------------------------
Reply to this message by going to Community
[http://community.jboss.org/message/560721#560721]
Start a new discussion in JBoss AS7 Development at Community
[http://community.jboss.org/choose-container!input.jspa?contentType=1&cont...]
13 years, 8 months