Pergunta

Eu construí um CFC projetado para servir como um cache dinâmico e envelhecido destinado a quase tudo o que vale a pena armazenar em cache. Consultas LDAP, resultados da função, matrizes, projetos, você escolhe. Tudo o que leva tempo ou recursos para calcular e é necessário mais de uma vez. Eu gostaria de poder fazer algumas coisas:

  • Compartilhe o CFC entre os aplicativos
  • Defina o escopo do cache (somente servidor / aplicativo / sessão / solicitação atual)
  • Use diferentes instâncias de cache ao mesmo tempo, na mesma solicitação
  • ser independente dos CFCs usando o componente de cache
  • Geralmente adere ao senso comum (desacoplamento, encapsulamento, ortogonalidade, bloqueio)

É claro que eu usaria uma instância de cache diferente para todas as tarefas distintas, mas gostaria de poder usar o mesmo CFC nos aplicativos. O próprio cache é (o que mais) uma estrutura, privada para a instância do cache. Como eu implementaria corretamente o cache e o bloqueio quando o escopo está sujeito a alterações?

Para travamento, eu uso o nome Nomeado ('CacheRead', 'CacheWrite') Atualmente, isso é seguro, mas me parece estranho. Por que eu gostaria de um bloqueio em todo o servidor para, digamos, uma operação somente de sessão? (Sim, talvez isso é acadêmico, mas de qualquer maneira.)

Passar o escopo do aplicativo como referência quando eu quero o cache no nível do aplicativo também parece a coisa errada a fazer. Existe uma maneira melhor?

Foi útil?

Solução

Entendo o seu desejo de evitar a passagem da estrutura de escopo real para a qual você deseja armazenar em cache, mas suas alternativas são limitadas. A primeira coisa que vem à mente é apenas passar o nome (uma string) do escopo em que você deseja que seu cache seja armazenado e avaliando. Por sua natureza, a avaliação é ineficiente e deve ser evitada. Dito isto, fiquei curioso como isso poderia ser realizado. Eu não tenho seu código, então acabei de fazer um CFC de abstração de "armazenamento" sujo (cache ignorado, pois é irrelevante para o que quero testar) aqui:

cache.cfc:

<cfcomponent>
    <cfset variables.cacheScope = "session" /><!--- default to session --->
    <cfset variables.cache = ""/>

    <cfscript>
    function init(scope){
        variables.cacheScope = arguments.scope;
        return this;
    }

    function cacheWrite(key, value){
        structInsert(evaluate(variables.cacheScope),arguments.key,arguments.value,true);
        return this;
    }

    function cacheRead(key){
        if (not structKeyExists(evaluate(variables.cacheScope), arguments.key)){
            return "";
        }else{
            variables.cache = evaluate(variables.cacheScope);
            return variables.cache[arguments.key];
        }
    }   
    </cfscript>
</cfcomponent>

E uma visão para testá -lo:

<!--- clear out any existing session vars --->
<cfset structClear(session)/>
<!--- show empty session struct --->
<cfdump var="#session#" label="session vars">
<!--- create storage object --->
<cfset cacher = createObject("component", "cache").init("session")/>
<!--- store a value --->
<cfset cacher.cacheWrite("foo", "bar")/>
<!--- read stored value --->
<cfset rtn = cacher.cacheRead("foo")/>
<!--- show values --->
<cfdump var="#rtn#">
<cfdump var="#session#" label="session vars">

Off Topic: Gosto de escrever minhas funções do setter para retornar "this" [como visto acima] para que eu possa encadear chamadas de método como jQuery. Parte da visão poderia ser tão facilmente escrita quanto:

<cfset rtn = createObject("component", "cache")
    .init("session")
    .cacheWrite("foo", "bar")
    .cacheRead("foo")/>

É interessante que isso seja possível, mas eu provavelmente não o usaria na produção devido ao custo aéreo da avaliação. Eu diria que esse é um motivo válido o suficiente para passar no escopo em que você deseja armazenar em cache.

Se você ainda está incomodado com isso (e talvez com razão?), Você poderia criar outro CFC que abstraia a leitura e a escrita do escopo desejado e passasse isso para o seu cache CFC como local de armazenamento (uma tarefa bem adequada para Coldspring).

Não sei ao certo por que você gostaria de ter um cache de uma única solicitação, quando você tiver o escopo da solicitação. Se o que você está procurando é uma maneira de armazenar em cache algo para a solicitação atual e a morrer logo depois, o escopo de solicitação pode ser o que você deseja. O cache geralmente é mais valioso quando abrange várias solicitações.

Outras dicas

Ok - desde que entendi mal sua pergunta inicialmente, excluí minha resposta anterior para não causar mais confusão.

Para responder sua pergunta sobre o bloqueio:

Os bloqueios nomeados devem ficar bem porque nem sempre precisam ter o mesmo nome. Você pode nomeá -los dinamicamente, dependendo do cache que você está acessando. Quando você precisa acessar um elemento da estrutura privada, você pode fazer algo como ter o bloqueio nomeado, use a chave como seu nome.

Dessa forma, a única vez que um bloqueio teria um efeito é se algo estava tentando acessar o mesmo cache pelo nome.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top