2010-07-03 2 views
6

[OR] UOW는 HTTP 요청 및 수정 작업에 의해 소비 할 수있는 StructureMap 라이프 사이클을 정의하는 방법StructureMap 지역 스레드 범위에서 배치 nHibenrate 세션 객체를 반환

I가 SM을 사용하여이 웹 응용 프로그램이 IoC. 내 nHibernate ISession 개체를 저장할 HybridHttpOrThreadLocalScoped 범위를 사용하고 있습니다. 이 요청은 웹 요청에 대한 요청마다 세션에서 잘 작동합니다.

하지만 quartz.net에서도 작업 일정을 잡았습니다. 작업은 동일한 작업 단위를 사용하여 ISession 객체를 가져옵니다. 이 시나리오에서는 스케줄러가 작업을 시작할 때 모든 것이 잘 작동하고 작업 스레드 ID가 반복 될 때까지 작업이 몇 번 올바르게 실행됩니다.

작업 일정이 잡히면 11, 12, 13 ID를 가진 스레드에서 실행 된 다음 스레드 ID 11으로 다시 시작됩니다. 이 시점에서 structuremap은 이미 삭제 된 세션 객체를 반환하고 "System.ObjectDisposedException : Session is closed!" 오류.

세션에서 볼 수 있듯이 세션은 스레드 로컬 저장소에 보관되며 작업 단위 종료시 세션을 처리 한 후에도 세션 개체는 여전히 스레드 로컬 저장소에 보관됩니다. 스레드가 종료 된 후 로컬 저장소가 지워지지 않고 동일한 ID를 가진 새 스레드가 만들어지면 구조체 맵은 이전 스레드 로컬 저장소 (새 스레드에 대해 지워야하는 세션)을 찾습니다. 나는 믿는다) 이미 버려진 세션 객체를 반환한다.

질문 :

  1. (종료)에 스레드 로컬 저장소를 삭제하는 방법이 있나요?
  2. 스레드 범위 개체에 해당하는 "ReleaseAndDisposeAllHttpScopedObjects"가 있습니까?
  3. 배치 된 객체를 무효화 (또는 꺼내기) 할 수있는 방법이 있습니까? 예를 들어 SM이 그것을 찾더라도 찾지 못하고 새로운 인스턴스를 만들어야합니까?

나는 나의 질문을 분명히하기를 희망한다. 이것은 내 시간의 두어 시간이 걸렸지 만 여전히 주위에 방법을 찾지 못했습니다. 내가 어떤 힌트를을 주셔서 감사합니다 :>

업데이트 : 가 나는 UOW HTTP 요청 및 수정 작업을 모두 StructureMap 작업에 의해 제공하기 위해 내 자신의 솔루션을 추가했다. 더 나은/더 쉽고 간단한 솔루션이 있다면 알려주십시오.

+0

StructureMap으로 석영 IJob을 관리하고 있습니까? –

+0

@Mauricio : 응용 프로그램에서 StructureMap을 사용하고 있습니다. StructeMap으로 석영 작업을 관리한다는 것은 무엇을 의미하는지 모르겠습니다.> – kaptan

+0

은 StructureMap에서 관리하는 Quartz IJob 인스턴스입니까? 다른 말로하면 : 당신은 당신의 직업을 컨테이너에 등록합니까? –

답변

1

왜 석영 작업에 대한 새 세션을 만들지 않습니까? 작업 단위 (UOW)는 일반적으로 db에 대한 트랜잭션 작업입니다. 쿼츠 작업이 웹 요청/응답과 트랜잭션 방식으로 관련되어 있다고 상상할 수는 없습니다. 새로운 세션을 만드는 것은 비용이 많이 들지 않습니다. 이게 가능한가?

+0

예. 각 석영 작업에 대해 새로운 세션을 만들고 싶습니다. 그러나 UoW라는 아이디어를 사용하고 있기 때문에 제 응용 프로그램에서 일관성있게 사용하고 싶습니다. 그래서 석영 작업을 위해 직접 세션을 만들고 싶지 않습니다. UoW 인스턴스를 만들고 싶습니다. 그러나 동시에 StructureMap을 사용하여 UoW의 인스턴스를 가져 오려고합니다. 이것이 내가 UoW를 위해 StructeMap에서 하이브리드 라이프 사이클을 정의하는 것을 끝내서 각각의 http 요청 또는 각 쿼츠 작업 실행에 대해 적절한 UoW를 반환하는 이유입니다. – kaptan

+0

@kaptan : @rcravens에 동의합니다. 내가 한 것은 ISessionFactory (ObjectFactory.GetInstance ())의 인스턴스를 가져 와서 작업이 시작되면 새 세션을 엽니 다. – LeftyX

2

저는 UMLW per UWW per Quartz 작업을 사용하여 StructMap 작업을 다시 한 번 보았습니다. 여기에서 내 솔루션을 공유하기로 결정했습니다.

그래서 나는 HTTP 컨텍스트가있을 때 UoW의 인스턴스를 얻고 http 컨텍스트가 없을 때 (예 : 석영 작업이있을 때와 같이) 스레드마다 UoW의 다른 인스턴스를 얻으려는 경우 StructureMap Hybrid 범위를 사용하려고했습니다 화재). 이와 같이 :

For<IUnitOfWork>().HybridHttpOrThreadLocalScoped().Use<UnitOfWork>(); 

http의 UoW가 정상적으로 작동했습니다. 문제는 스레드 당 UoW입니다.

다음과 같은 현상이 발생합니다. quratz 작업이 시작되면 스레드 풀에서 스레드를 당겨 해당 스레드를 사용하여 작업 실행을 시작합니다. 작업이 시작되면 나는 UoW를 요청한다. StructureMap은 UoW를 반환하기 위해 해당 스레드에 대한 로컬 저장소를 찾습니다. 그러나 어떤 스레드도 인스턴스를 생성하지 못하고 스레드의 로컬 저장소 아래에 저장합니다. UoW를 얻은 다음 perfom을 시작하고, Commit, Dispose를 수행합니다.

문제는 이전에 작업을 시작하기 위해 사용했던 스레드 풀에서 스레드를 끌어 와서 (UoW 사용) 문제가 발생합니다. 여기에 UoW를 요청하면 StructureMap은 캐시 (스레드 로컬 저장소)를보고 UoW를 찾아 반환합니다. 그러나 문제는 UoW가 폐기 된 것입니다!

그래서 우리는 스레드 자체가 삭제되지 않고 오래된 캐시 된 삭제 된 UoW를 보유하기 때문에 쿼츠 작업에 스레드 당 UoW를 실제로 사용할 수 없습니다. 기본적으로 스레드의 수명주기가 쿼츠 작업의 수명주기와 일치하지 않습니다. 그래서 석영 작업에 대한 내 자신의 라이프 사이클을 만들었습니다.

public class QuartzLifecycle : ILifecycle 
{ 

    public void EjectAll() 
    { 
     FindCache().DisposeAndClear(); 
    } 

    public IObjectCache FindCache() 
    { 
     return QuartzContext.Cache; 
    } 

    public string Scope { get { return "QuartzLifecycle"; } } 
} 

가 그럼 난 석영에 대한 HttpContext를 같은 몇 가지 상황에 맞는 클래스를 만들어야합니다

public class HybridHttpQuartzLifecycle : HttpLifecycleBase<HttpContextLifecycle, QuartzLifecycle> 
{ 
    public override string Scope { get { return "HybridHttpQuartzLifecycle"; } } 
} 

가 그럼 난 내 QuartzLifecyle 클래스를 생성 :

먼저 내 자신의 HTTP-석영 하이브리드 라이프 사이클 클래스를 생성 문맥 관련 정보를 보관 유지합니다. 그래서 QuartzContext 클래스를 만들었습니다. 쿼츠 작업이 실행되면 해당 작업의 JobExecutionContext가 QuartzContext에 등록되어야한다. 그런 다음 해당 JobExecutionContext 아래에서 StructureMap 인스턴스의 실제 캐시 (MainObjectCache)가 만들어집니다. 이렇게하면 작업 실행이 끝난 후에도 캐시가 사라지고 캐시에 UoW가 삭제되지 않습니다.

또한 _jobExecutionContext는 ThreadStatic이므로 QuartzContext에서 캐시를 요청할 때 동일한 스레드에 대해 저장된 JobExecutionContext에서 캐시를 반환합니다. 따라서 여러 작업이 동시에 실행될 때 JobExecutionContexts는 개별적으로 저장되며 실행중인 작업마다 별도의 캐시를 갖게됩니다.

public class QuartzContext 
{ 

    private static readonly string _cacheKey = "STRUCTUREMAP-INSTANCES"; 

    [ThreadStatic] 
    private static JobExecutionContext _jobExecutionContext; 

    protected static void Register(JobExecutionContext jobExecutionContext) 
    { 
     _jobExecutionContext = jobExecutionContext; 
     _jobExecutionContext.Put(_cacheKey, new MainObjectCache()); 
    } 

    public static IObjectCache Cache 
    { 
     get 
     { 
      return (IObjectCache)_jobExecutionContext.Get(_cacheKey); 
     } 
    } 
} 

다른 작업에서 파생 된 BaseJobSingleSession이라는 추상 클래스가 있습니다. 이 클래스는 QuartzContext 클래스를 확장한다. 작업이 시작되면 JobExecutionContext를 등록한다는 것을 알 수 있습니다.

abstract class BaseJobSingleSession : QuartzContext, IStatefulJob 
{ 
    public override void Execute(JobExecutionContext context) 
    { 
     Register(context); 
     IUnitOfWork unitOfWork = ObjectFactory.GetInstance<IUnitOfWork>(); 

     try 
     { 
      unitOfWork.Begin(); 

      // do stuff .... 

      unitOfWork.Commit(); 
     } 
     catch (Exception exception) 
     { 
      unitOfWork.RollBack(); 

     } 
     finally 
     { 
      unitOfWork.Dispose(); 
     } 
    } 
} 

마지막으로 나는 UOW에 대한 라이프 사이클 정의 : (. 내가 StructureMap 소스 코드를 들여다 수명주기와 상황에 맞는 클래스에 대한 아이디어를 얻을 수)
For<IUnitOfWork>().LifecycleIs(new HybridHttpQuartzLifecycle()).Use<UnitOfWork>(); 

공유하세요 귀하의 아이디어, 의견 및 제안 :>